diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 4fea8c35a6..3ff5a8206b 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -36,6 +36,7 @@ import ( "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/kubeconfig" "k8s.io/minikube/pkg/util" + pkgutil "k8s.io/minikube/pkg/util" ) const ( @@ -96,6 +97,7 @@ func runStart(cmd *cobra.Command, args []string) { HostOnlyCIDR: viper.GetString(hostOnlyCIDR), HypervVirtualSwitch: viper.GetString(hypervVirtualSwitch), KvmNetwork: viper.GetString(kvmNetwork), + Downloader: pkgutil.DefaultDownloader{}, } var host *host.Host diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index 090e55115f..d232535544 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -18,7 +18,6 @@ package cluster import ( "bytes" - "crypto" "encoding/json" "flag" "fmt" @@ -38,7 +37,6 @@ import ( "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/state" "github.com/golang/glog" - download "github.com/jimmidyson/go-download" "github.com/pkg/browser" "github.com/pkg/errors" "k8s.io/client-go/1.5/kubernetes" @@ -178,31 +176,6 @@ type sshAble interface { RunSSHCommand(string) (string, error) } -// MachineConfig contains the parameters used to start a cluster. -type MachineConfig struct { - MinikubeISO string - Memory int - CPUs int - DiskSize int - VMDriver string - DockerEnv []string // Each entry is formatted as KEY=VALUE. - InsecureRegistry []string - RegistryMirror []string - HostOnlyCIDR string // Only used by the virtualbox driver - HypervVirtualSwitch string - KvmNetwork string // Only used by the KVM driver -} - -// KubernetesConfig contains the parameters used to configure the VM Kubernetes. -type KubernetesConfig struct { - KubernetesVersion string - NodeIP string - ContainerRuntime string - NetworkPlugin string - FeatureGates string - ExtraOptions util.ExtraOptionSlice -} - // StartCluster starts a k8s cluster on the specified Host. func StartCluster(h sshAble, kubernetesConfig KubernetesConfig) error { startCommand, err := GetStartCommand(kubernetesConfig) @@ -315,7 +288,7 @@ func engineOptions(config MachineConfig) *engine.Options { func createVirtualboxHost(config MachineConfig) drivers.Driver { d := virtualbox.NewDriver(constants.MachineName, constants.Minipath) - d.Boot2DockerURL = config.GetISOFileURI() + d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Memory = config.Memory d.CPU = config.CPUs d.DiskSize = int(config.DiskSize) @@ -323,77 +296,11 @@ func createVirtualboxHost(config MachineConfig) drivers.Driver { return d } -func (m *MachineConfig) CacheMinikubeISOFromURL() error { - options := download.FileOptions{ - Mkdirs: download.MkdirAll, - Options: download.Options{ - ProgressBars: &download.ProgressBarOptions{ - MaxWidth: 80, - }, - }, - } - - // Validate the ISO if it was the default URL, before writing it to disk. - if m.MinikubeISO == constants.DefaultIsoUrl { - options.Checksum = constants.DefaultIsoShaUrl - options.ChecksumHash = crypto.SHA256 - } - - fmt.Println("Downloading Minikube ISO") - if err := download.ToFile(m.MinikubeISO, m.GetISOCacheFilepath(), options); err != nil { - return errors.Wrap(err, "Error downloading Minikube ISO") - } - - return nil -} - -func (m *MachineConfig) ShouldCacheMinikubeISO() bool { - // store the miniube-iso inside the .minikube dir - - urlObj, err := url.Parse(m.MinikubeISO) - if err != nil { - return false - } - if urlObj.Scheme == fileScheme { - return false - } - if m.IsMinikubeISOCached() { - return false - } - return true -} - -func (m *MachineConfig) GetISOCacheFilepath() string { - return filepath.Join(constants.Minipath, "cache", "iso", filepath.Base(m.MinikubeISO)) -} - -func (m *MachineConfig) GetISOFileURI() string { - urlObj, err := url.Parse(m.MinikubeISO) - if err != nil { - return m.MinikubeISO - } - if urlObj.Scheme == fileScheme { - return m.MinikubeISO - } - isoPath := filepath.Join(constants.Minipath, "cache", "iso", filepath.Base(m.MinikubeISO)) - // As this is a file URL there should be no backslashes regardless of platform running on. - return "file://" + filepath.ToSlash(isoPath) -} - -func (m *MachineConfig) IsMinikubeISOCached() bool { - if _, err := os.Stat(m.GetISOCacheFilepath()); os.IsNotExist(err) { - return false - } - return true -} - func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) { var driver interface{} - if config.ShouldCacheMinikubeISO() { - if err := config.CacheMinikubeISOFromURL(); err != nil { - return nil, errors.Wrap(err, "Error attempting to cache minikube iso from url") - } + if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil { + return nil, errors.Wrap(err, "Error attempting to cache minikube ISO from URL") } switch config.VMDriver { @@ -510,11 +417,6 @@ func CreateSSHShell(api libmachine.API, args []string) error { return client.Shell(strings.Join(args, " ")) } -type ipPort struct { - IP string - Port int32 -} - func GetServiceURLsForService(api libmachine.API, namespace, service string, t *template.Template) ([]string, error) { host, err := CheckIfApiExistsAndLoad(api) if err != nil { @@ -547,7 +449,13 @@ func getServiceURLsWithClient(client *kubernetes.Clientset, ip, namespace, servi for _, port := range ports { var doc bytes.Buffer - err = t.Execute(&doc, ipPort{ip, port}) + err = t.Execute(&doc, struct { + IP string + Port int32 + }{ + ip, + port, + }) if err != nil { return nil, err } diff --git a/pkg/minikube/cluster/cluster_darwin.go b/pkg/minikube/cluster/cluster_darwin.go index ee0e28534a..4a38090a48 100644 --- a/pkg/minikube/cluster/cluster_darwin.go +++ b/pkg/minikube/cluster/cluster_darwin.go @@ -24,7 +24,7 @@ import ( func createVMwareFusionHost(config MachineConfig) drivers.Driver { d := vmwarefusion.NewDriver(constants.MachineName, constants.Minipath).(*vmwarefusion.Driver) - d.Boot2DockerURL = config.GetISOFileURI() + d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Memory = config.Memory d.CPU = config.CPUs d.DiskSize = config.DiskSize @@ -60,7 +60,7 @@ func createXhyveHost(config MachineConfig) *xhyveDriver { }, Memory: config.Memory, CPU: config.CPUs, - Boot2DockerURL: config.GetISOFileURI(), + Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO), BootCmd: "loglevel=3 user=docker console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 base host=" + constants.MachineName, DiskSize: int64(config.DiskSize), Virtio9p: true, diff --git a/pkg/minikube/cluster/cluster_linux.go b/pkg/minikube/cluster/cluster_linux.go index 61cbf55e20..dfec618f97 100644 --- a/pkg/minikube/cluster/cluster_linux.go +++ b/pkg/minikube/cluster/cluster_linux.go @@ -49,7 +49,7 @@ func createKVMHost(config MachineConfig) *kvmDriver { CPU: config.CPUs, Network: config.KvmNetwork, PrivateNetwork: "docker-machines", - Boot2DockerURL: config.GetISOFileURI(), + Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO), DiskSize: config.DiskSize, DiskPath: filepath.Join(constants.Minipath, "machines", constants.MachineName, fmt.Sprintf("%s.img", constants.MachineName)), ISO: filepath.Join(constants.Minipath, "machines", constants.MachineName, "boot2docker.iso"), diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go index 200c75b40e..61a4d601ef 100644 --- a/pkg/minikube/cluster/cluster_test.go +++ b/pkg/minikube/cluster/cluster_test.go @@ -42,9 +42,15 @@ import ( "k8s.io/minikube/pkg/minikube/tests" ) +type MockDownloader struct{} + +func (d MockDownloader) GetISOFileURI(isoURL string) string { return "" } +func (d MockDownloader) CacheMinikubeISOFromURL(isoURL string) error { return nil } + var defaultMachineConfig = MachineConfig{ VMDriver: constants.DefaultVMDriver, MinikubeISO: constants.DefaultIsoUrl, + Downloader: MockDownloader{}, } func TestCreateHost(t *testing.T) { @@ -225,8 +231,9 @@ func TestStartHostConfig(t *testing.T) { provision.SetDetector(md) config := MachineConfig{ - VMDriver: constants.DefaultVMDriver, - DockerEnv: []string{"FOO=BAR"}, + VMDriver: constants.DefaultVMDriver, + DockerEnv: []string{"FOO=BAR"}, + Downloader: MockDownloader{}, } h, err := StartHost(api, config) diff --git a/pkg/minikube/cluster/cluster_windows.go b/pkg/minikube/cluster/cluster_windows.go index b93b850f04..8546a5053d 100644 --- a/pkg/minikube/cluster/cluster_windows.go +++ b/pkg/minikube/cluster/cluster_windows.go @@ -24,7 +24,7 @@ import ( func createHypervHost(config MachineConfig) drivers.Driver { d := hyperv.NewDriver(constants.MachineName, constants.Minipath) - d.Boot2DockerURL = config.GetISOFileURI() + d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.VSwitch = config.HypervVirtualSwitch d.MemSize = config.Memory d.CPU = config.CPUs diff --git a/pkg/minikube/cluster/types.go b/pkg/minikube/cluster/types.go new file mode 100644 index 0000000000..ddbf5f6f13 --- /dev/null +++ b/pkg/minikube/cluster/types.go @@ -0,0 +1,45 @@ +/* +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 "k8s.io/minikube/pkg/util" + +// MachineConfig contains the parameters used to start a cluster. +type MachineConfig struct { + MinikubeISO string + Memory int + CPUs int + DiskSize int + VMDriver string + DockerEnv []string // Each entry is formatted as KEY=VALUE. + InsecureRegistry []string + RegistryMirror []string + HostOnlyCIDR string // Only used by the virtualbox driver + HypervVirtualSwitch string + KvmNetwork string // Only used by the KVM driver + Downloader util.ISODownloader +} + +// KubernetesConfig contains the parameters used to configure the VM Kubernetes. +type KubernetesConfig struct { + KubernetesVersion string + NodeIP string + ContainerRuntime string + NetworkPlugin string + FeatureGates string + ExtraOptions util.ExtraOptionSlice +} diff --git a/pkg/util/downloader.go b/pkg/util/downloader.go new file mode 100644 index 0000000000..caeadd22fd --- /dev/null +++ b/pkg/util/downloader.go @@ -0,0 +1,108 @@ +/* +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" + "fmt" + "net/url" + "os" + "path/filepath" + + "github.com/golang/glog" + download "github.com/jimmidyson/go-download" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/constants" +) + +const fileScheme = "file" + +type ISODownloader interface { + GetISOFileURI(isoURL string) string + CacheMinikubeISOFromURL(isoURL string) error +} + +type DefaultDownloader struct{} + +func (f DefaultDownloader) GetISOFileURI(isoURL string) string { + urlObj, err := url.Parse(isoURL) + if err != nil { + return isoURL + } + if urlObj.Scheme == fileScheme { + return isoURL + } + isoPath := filepath.Join(constants.Minipath, "cache", "iso", filepath.Base(isoURL)) + // As this is a file URL there should be no backslashes regardless of platform running on. + return "file://" + filepath.ToSlash(isoPath) +} + +func (f DefaultDownloader) CacheMinikubeISOFromURL(isoURL string) error { + if !f.shouldCacheMinikubeISO(isoURL) { + glog.Infof("Not caching ISO, using %s", isoURL) + return nil + } + + options := download.FileOptions{ + Mkdirs: download.MkdirAll, + Options: download.Options{ + ProgressBars: &download.ProgressBarOptions{ + MaxWidth: 80, + }, + }, + } + + // Validate the ISO if it was the default URL, before writing it to disk. + if isoURL == constants.DefaultIsoUrl { + options.Checksum = constants.DefaultIsoShaUrl + options.ChecksumHash = crypto.SHA256 + } + + fmt.Println("Downloading Minikube ISO") + if err := download.ToFile(isoURL, f.getISOCacheFilepath(isoURL), options); err != nil { + return errors.Wrap(err, "Error downloading Minikube ISO") + } + + return nil +} + +func (f DefaultDownloader) shouldCacheMinikubeISO(isoURL string) bool { + // store the miniube-iso inside the .minikube dir + + urlObj, err := url.Parse(isoURL) + if err != nil { + return false + } + if urlObj.Scheme == fileScheme { + return false + } + if f.isMinikubeISOCached(isoURL) { + return false + } + return true +} + +func (f DefaultDownloader) getISOCacheFilepath(isoURL string) string { + return filepath.Join(constants.Minipath, "cache", "iso", filepath.Base(isoURL)) +} + +func (f DefaultDownloader) isMinikubeISOCached(isoURL string) bool { + if _, err := os.Stat(f.getISOCacheFilepath(isoURL)); os.IsNotExist(err) { + return false + } + return true +}