diff --git a/Makefile b/Makefile index 6d96df5f340a..4571aeb5a8e0 100755 --- a/Makefile +++ b/Makefile @@ -21,8 +21,8 @@ VERSION ?= v$(RAW_VERSION) KUBERNETES_VERSION ?= $(shell egrep "DefaultKubernetesVersion =" pkg/minikube/constants/constants.go | cut -d \" -f2) KIC_VERSION ?= $(shell egrep "Version =" pkg/drivers/kic/types.go | cut -d \" -f2) -PRELOADED_TARBALL_VERSION ?= $(shell egrep "Version =" pkg/minikube/preload/constants.go | cut -d \" -f2) -PRELOADED_VOLUMES_GCS_BUCKET ?= $(shell egrep "PreloadedVolumeTarballsBucket =" pkg/minikube/constants/constants.go | cut -d \" -f2) +PRELOADED_TARBALL_VERSION ?= $(shell egrep "PreloadVersion =" pkg/minikube/download/preload.go | cut -d \" -f2) +PRELOADED_VOLUMES_GCS_BUCKET ?= $(shell egrep "PreloadBucket =" pkg/minikube/download/preload.go | cut -d \" -f2) # Default to .0 for higher cache hit rates, as build increments typically don't require new ISO versions ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).3 diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 605534885f8b..9c296c8b196a 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -43,10 +43,10 @@ import ( cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config" "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil" "k8s.io/minikube/pkg/minikube/bootstrapper/images" - "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/kubeconfig" @@ -154,7 +154,7 @@ func initMinikubeFlags() { startCmd.Flags().String(humanReadableDiskSize, defaultDiskSize, "Disk size allocated to the minikube VM (format: [], where unit = b, k, m or g).") startCmd.Flags().Bool(downloadOnly, false, "If true, only download and cache files for later use - don't install or start anything.") startCmd.Flags().Bool(cacheImages, true, "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.") - startCmd.Flags().String(isoURL, constants.DefaultISOURL, "Location of the minikube iso.") + startCmd.Flags().StringSlice(isoURL, download.DefaultISOURLs(), "Locations to fetch the minikube ISO from.") startCmd.Flags().Bool(keepContext, false, "This will keep the existing kubectl context and will create a minikube context.") startCmd.Flags().Bool(embedCerts, false, "if true, will embed the certs in kubeconfig.") startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd).") @@ -321,7 +321,13 @@ func runStart(cmd *cobra.Command, args []string) { return } - cacheISO(&mc, driverName) + if !driver.BareMetal(driverName) && !driver.IsKIC(driverName) { + url, err := download.ISO(viper.GetStringSlice(isoURL)) + if err != nil { + exit.WithError("Failed to cache ISO", err) + } + mc.MinikubeISO = url + } if viper.GetBool(nativeSSH) { ssh.SetDefaultClient(ssh.Native) @@ -355,14 +361,6 @@ func updateDriver(driverName string) { } } -func cacheISO(cfg *config.ClusterConfig, driverName string) { - if !driver.BareMetal(driverName) && !driver.IsKIC(driverName) { - if err := cluster.CacheISO(*cfg); err != nil { - exit.WithError("Failed to cache ISO", err) - } - } -} - func displayVersion(version string) { prefix := "" if viper.GetString(config.ProfileName) != constants.DefaultClusterName { @@ -796,7 +794,6 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) Name: viper.GetString(config.ProfileName), KeepContext: viper.GetBool(keepContext), EmbedCerts: viper.GetBool(embedCerts), - MinikubeISO: viper.GetString(isoURL), Memory: pkgutil.CalculateSizeInMB(viper.GetString(memory)), CPUs: viper.GetInt(cpus), DiskSize: pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)), @@ -817,7 +814,6 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) KVMQemuURI: viper.GetString(kvmQemuURI), KVMGPU: viper.GetBool(kvmGPU), KVMHidden: viper.GetBool(kvmHidden), - Downloader: pkgutil.DefaultDownloader{}, DisableDriverMounts: viper.GetBool(disableDriverMounts), UUID: viper.GetString(uuid), NoVTXCheck: viper.GetBool(noVTXCheck), diff --git a/go.mod b/go.mod index 9b876466ee79..6503b4285f54 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/cheggaaa/pb/v3 v3.0.1 github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect + github.com/docker/cli v0.0.0-20200303162255-7d407207c304 // indirect github.com/docker/docker v1.13.1 github.com/docker/go-units v0.4.0 github.com/docker/machine v0.7.1-0.20190718054102-a555e4f7a8f5 // version is 0.7.1 to pin to a555e4f7a8f5 @@ -24,15 +25,12 @@ require ( github.com/google/go-cmp v0.3.0 github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 github.com/googleapis/gnostic v0.3.0 // indirect - github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect github.com/hashicorp/go-getter v1.4.0 - github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 // indirect github.com/hashicorp/go-retryablehttp v0.5.4 github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8 github.com/imdario/mergo v0.3.8 // indirect github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 // indirect - github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d // indirect @@ -66,18 +64,20 @@ require ( github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 golang.org/x/build v0.0.0-20190927031335-2835ba2e683f - golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 + golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 + golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e golang.org/x/sys v0.0.0-20191010194322-b09406accb47 golang.org/x/text v0.3.2 google.golang.org/api v0.9.0 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect + gotest.tools/v3 v3.0.2 // indirect k8s.io/api v0.17.3 k8s.io/apimachinery v0.17.3 k8s.io/client-go v0.17.3 k8s.io/kubectl v0.0.0 k8s.io/kubernetes v1.17.3 - k8s.io/utils v0.0.0-20200122174043-1e243dd1a584 // indirect + k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab // indirect sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.0+incompatible ) diff --git a/go.sum b/go.sum index 8d6e6da84bcf..43d58cc92596 100644 --- a/go.sum +++ b/go.sum @@ -144,6 +144,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200303162255-7d407207c304 h1:A7SYzidcyuQ/yS4wezWGYeUioUFJQk8HYWY9aMYTF4I= +github.com/docker/cli v0.0.0-20200303162255-7d407207c304/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE= @@ -346,12 +348,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 h1:VIq8E7fMiC4h3agg0ya56L0jHn7QisZZcWZXVKJb9jQ= -github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= @@ -386,8 +384,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 h1:XboatR7lasl05yel5hNXF7kQBw2oFUGdMztcgisfhNU= github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6/go.mod h1:RmeVYf9XrPRbRc3XIx0gLYA8qOFvNoPOfaEZduRlEp4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b h1:3TknJxYSK1eDe21QorC3C2Yz8jylk6vlJG9YABnFzkU= -github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b/go.mod h1:I3WsAhNNoG7a/d8HMlYUywJJlfOs/+/83NEUjuDp4lc= github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -735,6 +731,8 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -780,6 +778,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= @@ -864,6 +864,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -944,6 +945,8 @@ gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= +gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -996,8 +999,8 @@ k8s.io/sample-apiserver v0.17.3/go.mod h1:cn/rvFIttGNqy1v88B5ZlDAbyyqDOoF7JHSwPi k8s.io/system-validators v1.0.4/go.mod h1:HgSgTg4NAGNoYYjKsUyk52gdNi2PVDswQ9Iyn66R7NI= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200122174043-1e243dd1a584 h1:3tT5mBZNurtd5BoYrPBII3Sa8n7T2w405qdTQvr3vmY= -k8s.io/utils v0.0.0-20200122174043-1e243dd1a584/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab h1:I3f2hcBrepGRXI1z4sukzAb8w1R4eqbsHrAsx06LGYM= +k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/pkg/drivers/kic/kic.go b/pkg/drivers/kic/kic.go index a46a6c4c8358..f33bda1f3dfb 100644 --- a/pkg/drivers/kic/kic.go +++ b/pkg/drivers/kic/kic.go @@ -36,7 +36,7 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/preload" + "k8s.io/minikube/pkg/minikube/download" ) // Driver represents a kic driver https://minikube.sigs.k8s.io/docs/reference/drivers/docker @@ -103,7 +103,7 @@ func (d *Driver) Create() error { t := time.Now() glog.Infof("Starting extracting preloaded images to volume") // Extract preloaded images to container - if err := oci.ExtractTarballToVolume(preload.TarballFilepath(d.NodeConfig.KubernetesVersion), params.Name, BaseImage); err != nil { + if err := oci.ExtractTarballToVolume(download.TarballPath(d.NodeConfig.KubernetesVersion), params.Name, BaseImage); err != nil { glog.Infof("Unable to extract preloaded tarball to volume: %v", err) } else { glog.Infof("Took %f seconds to extract preloaded images to volume", time.Since(t).Seconds()) diff --git a/pkg/minikube/bootstrapper/bsutil/binaries.go b/pkg/minikube/bootstrapper/bsutil/binaries.go index 0b4d4e72b6c9..32b9a166a276 100644 --- a/pkg/minikube/bootstrapper/bsutil/binaries.go +++ b/pkg/minikube/bootstrapper/bsutil/binaries.go @@ -30,6 +30,7 @@ import ( "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/vmpath" ) @@ -53,7 +54,7 @@ func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error { for _, name := range constants.KubernetesReleaseBinaries { name := name g.Go(func() error { - src, err := machine.CacheBinary(name, cfg.KubernetesVersion, "linux", runtime.GOARCH) + src, err := download.Binary(name, cfg.KubernetesVersion, "linux", runtime.GOARCH) if err != nil { return errors.Wrapf(err, "downloading %s", name) } diff --git a/pkg/minikube/cluster/iso.go b/pkg/minikube/cluster/iso.go deleted file mode 100644 index 15c06b4a3765..000000000000 --- a/pkg/minikube/cluster/iso.go +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright 2020 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/minikube/config" - "k8s.io/minikube/pkg/minikube/driver" -) - -// CacheISO downloads and caches ISO. -func CacheISO(cfg config.ClusterConfig) error { - if driver.BareMetal(cfg.Driver) { - return nil - } - return cfg.Downloader.CacheMinikubeISOFromURL(cfg.MinikubeISO) -} diff --git a/pkg/minikube/config/types.go b/pkg/minikube/config/types.go index 868ad8842ee0..d58bc92485e2 100644 --- a/pkg/minikube/config/types.go +++ b/pkg/minikube/config/types.go @@ -20,7 +20,6 @@ import ( "net" "github.com/blang/semver" - "k8s.io/minikube/pkg/util" ) // Profile represents a minikube profile @@ -49,13 +48,12 @@ type ClusterConfig struct { HypervVirtualSwitch string HypervUseExternalSwitch bool HypervExternalAdapter string - KVMNetwork string // Only used by the KVM driver - KVMQemuURI string // Only used by kvm2 - KVMGPU bool // Only used by kvm2 - KVMHidden bool // Only used by kvm2 - Downloader util.ISODownloader `json:"-"` - DockerOpt []string // Each entry is formatted as KEY=VALUE. - DisableDriverMounts bool // Only used by virtualbox + KVMNetwork string // Only used by the KVM driver + KVMQemuURI string // Only used by kvm2 + KVMGPU bool // Only used by kvm2 + KVMHidden bool // Only used by kvm2 + DockerOpt []string // Each entry is formatted as KEY=VALUE. + DisableDriverMounts bool // Only used by virtualbox NFSShare []string NFSSharesRoot string UUID string // Only used by hyperkit to restore the mac address diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index c2489c31294c..0f6af77d31a1 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -17,13 +17,11 @@ limitations under the License. package constants import ( - "fmt" "path/filepath" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" "k8s.io/minikube/pkg/minikube/localpath" - minikubeVersion "k8s.io/minikube/pkg/version" ) const ( @@ -60,9 +58,6 @@ const ( MinikubeActiveDockerdEnv = "MINIKUBE_ACTIVE_DOCKERD" // PodmanVarlinkBridgeEnv is used for podman settings PodmanVarlinkBridgeEnv = "PODMAN_VARLINK_BRIDGE" - - // PreloadedVolumeTarballsBucket is the name of the GCS bucket where preloaded volume tarballs exist - PreloadedVolumeTarballsBucket = "minikube-preloaded-volume-tarballs" ) var ( @@ -75,10 +70,6 @@ var ( // SHASuffix is the suffix of a SHA-256 checksum file SHASuffix = ".sha256" - // DefaultISOURL is the default location of the minikube.iso file - DefaultISOURL = fmt.Sprintf("https://storage.googleapis.com/%s/minikube-%s.iso", minikubeVersion.GetISOPath(), minikubeVersion.GetISOVersion()) - // DefaultISOSHAURL is the default location of the minikube.iso.sha256 file - DefaultISOSHAURL = DefaultISOURL + SHASuffix // DockerDaemonEnvs is list of docker-daemon related environment variables. DockerDaemonEnvs = [3]string{DockerHostEnv, DockerTLSVerifyEnv, DockerCertPathEnv} diff --git a/pkg/minikube/download/binary.go b/pkg/minikube/download/binary.go new file mode 100644 index 000000000000..0eae5600cd96 --- /dev/null +++ b/pkg/minikube/download/binary.go @@ -0,0 +1,83 @@ +/* +Copyright 2020 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 download + +import ( + "fmt" + "os" + "path" + "runtime" + + "github.com/blang/semver" + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/localpath" +) + +// binaryWithChecksumURL gets the location of a Kubernetes binary +func binaryWithChecksumURL(binaryName, version, osName, archName string) (string, error) { + base := fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) + v, err := semver.Make(version[1:]) + if err != nil { + return "", err + } + + if v.GTE(semver.MustParse("1.17.0")) { + return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base), nil + } + return fmt.Sprintf("%s?checksum=file:%s.sha1", base, base), nil +} + +// Binary will download a binary onto the host +func Binary(binary, version, osName, archName string) (string, error) { + targetDir := localpath.MakeMiniPath("cache", osName, version) + targetFilepath := path.Join(targetDir, binary) + + url, err := binaryWithChecksumURL(binary, version, osName, archName) + if err != nil { + return "", err + } + + if _, err := os.Stat(targetFilepath); err == nil { + glog.Infof("Not caching binary, using %s", url) + return targetFilepath, nil + } + + if err = os.MkdirAll(targetDir, 0777); err != nil { + return "", errors.Wrapf(err, "mkdir %s", targetDir) + } + + client := &getter.Client{ + Src: url, + Dst: targetFilepath, + Mode: getter.ClientModeFile, + Options: []getter.ClientOption{getter.WithProgress(DefaultProgressBar)}, + } + + glog.Infof("Downloading: %+v", client) + if err := client.Get(); err != nil { + return "", errors.Wrapf(err, "download failed: %s", url) + } + + if osName == runtime.GOOS && archName == runtime.GOARCH { + if err = os.Chmod(targetFilepath, 0755); err != nil { + return "", errors.Wrapf(err, "chmod +x %s", targetFilepath) + } + } + return targetFilepath, nil +} diff --git a/pkg/minikube/download/binary_test.go b/pkg/minikube/download/binary_test.go new file mode 100644 index 000000000000..79c23131c2f5 --- /dev/null +++ b/pkg/minikube/download/binary_test.go @@ -0,0 +1,117 @@ +/* +Copyright 2020 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 download + +import ( + "io/ioutil" + "os" + "runtime" + "testing" +) + +func TestCacheBinary(t *testing.T) { + oldMinikubeHome := os.Getenv("MINIKUBE_HOME") + defer os.Setenv("MINIKUBE_HOME", oldMinikubeHome) + + minikubeHome, err := ioutil.TempDir("/tmp", "") + if err != nil { + t.Fatalf("error during creating tmp dir: %v", err) + } + defer os.RemoveAll(minikubeHome) + noWritePermDir, err := ioutil.TempDir("/tmp", "") + if err != nil { + t.Fatalf("error during creating tmp dir: %v", err) + } + defer os.RemoveAll(noWritePermDir) + err = os.Chmod(noWritePermDir, 0000) + if err != nil { + t.Fatalf("error (%v) during changing permissions of dir %v", err, noWritePermDir) + } + + var tc = []struct { + desc, version, osName, archName string + minikubeHome, binary, description string + err bool + }{ + { + desc: "ok kubeadm", + version: "v1.16.0", + osName: "linux", + archName: runtime.GOARCH, + binary: "kubeadm", + err: false, + minikubeHome: minikubeHome, + }, + { + desc: "minikube home in dir without perms and arm runtime", + version: "v1.16.0", + osName: runtime.GOOS, + archName: "arm", + binary: "kubectl", + err: true, + minikubeHome: noWritePermDir, + }, + { + desc: "minikube home in dir without perms", + version: "v1.16.0", + osName: runtime.GOOS, + archName: runtime.GOARCH, + binary: "kubectl", + err: true, + minikubeHome: noWritePermDir, + }, + { + desc: "binary foo", + version: "v1.16.0", + osName: runtime.GOOS, + archName: runtime.GOARCH, + binary: "foo", + err: true, + minikubeHome: minikubeHome, + }, + { + desc: "version 9000", + version: "v9000", + osName: runtime.GOOS, + archName: runtime.GOARCH, + binary: "foo", + err: true, + minikubeHome: minikubeHome, + }, + { + desc: "bad os", + version: "v1.16.0", + osName: "no-such-os", + archName: runtime.GOARCH, + binary: "kubectl", + err: true, + minikubeHome: minikubeHome, + }, + } + for _, test := range tc { + t.Run(test.desc, func(t *testing.T) { + os.Setenv("MINIKUBE_HOME", test.minikubeHome) + _, err := Binary(test.binary, test.version, test.osName, test.archName) + if err != nil && !test.err { + t.Fatalf("Got unexpected error %v", err) + } + if err == nil && test.err { + t.Fatalf("Expected error but got %v", err) + } + }) + } +} diff --git a/pkg/minikube/download/driver.go b/pkg/minikube/download/driver.go new file mode 100644 index 000000000000..b167987ae7d7 --- /dev/null +++ b/pkg/minikube/download/driver.go @@ -0,0 +1,53 @@ +/* +Copyright 2020 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 download + +import ( + "fmt" + "os" + + "github.com/blang/semver" + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/out" +) + +func driverWithChecksumURL(name string, v semver.Version) string { + base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, name) + return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base) +} + +// Driver downloads an arbitrary driver +func Driver(name string, destination string, v semver.Version) error { + out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": name}) + os.Remove(destination) + url := driverWithChecksumURL(name, v) + client := &getter.Client{ + Src: url, + Dst: destination, + Mode: getter.ClientModeFile, + Options: []getter.ClientOption{getter.WithProgress(DefaultProgressBar)}, + } + + glog.Infof("Downloading: %+v", client) + if err := client.Get(); err != nil { + return errors.Wrapf(err, "download failed: %s", url) + } + // Give downloaded drivers a baseline decent file permission + return os.Chmod(destination, 0755) +} diff --git a/pkg/minikube/download/iso.go b/pkg/minikube/download/iso.go new file mode 100644 index 000000000000..bc3e16077d26 --- /dev/null +++ b/pkg/minikube/download/iso.go @@ -0,0 +1,149 @@ +/* +Copyright 2020 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 download + +import ( + "fmt" + "net/url" + "os" + "path" + "path/filepath" + "strings" + "time" + + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/juju/mutex" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/localpath" + "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/util/lock" + "k8s.io/minikube/pkg/version" +) + +const fileScheme = "file" + +// DefaultISOURLs returns a list of ISO URL's to consult by default, in priority order +func DefaultISOURLs() []string { + v := version.GetISOVersion() + return []string{ + fmt.Sprintf("https://storage.googleapis.com/minikube/iso/minikube-%s.iso", v), + fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/%s/minikube-%s.iso", v, v), + fmt.Sprintf("https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-%s.iso", v), + } +} + +// LocalISOResource returns a local file:// URI equivalent for a local or remote ISO path +func LocalISOResource(isoURL string) string { + u, err := url.Parse(isoURL) + if err != nil { + fake := "file://" + filepath.ToSlash(isoURL) + glog.Errorf("%s is not a URL! Returning %s", isoURL, fake) + return fake + } + + if u.Scheme == fileScheme { + return isoURL + } + + return fileURI(localISOPath(u)) +} + +// fileURI returns a file:// URI for a path +func fileURI(path string) string { + return "file://" + filepath.ToSlash(path) +} + +// localISOPath returns where an ISO should be stored locally +func localISOPath(u *url.URL) string { + if u.Scheme == fileScheme { + return u.String() + } + + return filepath.Join(localpath.MiniPath(), "cache", "iso", path.Base(u.Path)) +} + +// ISO downloads and returns the path to the downloaded ISO +func ISO(urls []string) (string, error) { + out.T(out.ISODownload, "Downloading VM boot image ...") + errs := map[string]string{} + + for _, url := range urls { + err := downloadISO(url) + if err != nil { + glog.Errorf("Unable to download %s: %v", url, err) + errs[url] = err.Error() + continue + } + return url, nil + } + + var msg strings.Builder + msg.WriteString("unable to cache ISO: \n") + for u, err := range errs { + msg.WriteString(fmt.Sprintf(" %s: %s\n", u, err)) + } + + return "", fmt.Errorf(msg.String()) +} + +// downloadISO downloads an ISO URL +func downloadISO(isoURL string) error { + u, err := url.Parse(isoURL) + if err != nil { + return errors.Wrapf(err, "url.parse %q", isoURL) + } + + // It's already downloaded + if u.Scheme == fileScheme { + return nil + } + + // Lock before we check for existence to avoid thundering herd issues + dst := localISOPath(u) + spec := lock.PathMutexSpec(dst) + spec.Timeout = 10 * time.Minute + glog.Infof("acquiring lock: %+v", spec) + releaser, err := mutex.Acquire(spec) + if err != nil { + return errors.Wrapf(err, "unable to acquire lock for %+v", spec) + } + defer releaser.Release() + + if _, err := os.Stat(dst); err == nil { + return nil + } + + urlWithChecksum := isoURL + "?checksum=file:" + isoURL + ".sha256" + + // Predictable temp destination so that resume can function + tmpDst := dst + ".download" + + opts := []getter.ClientOption{getter.WithProgress(DefaultProgressBar)} + client := &getter.Client{ + Src: urlWithChecksum, + Dst: tmpDst, + Mode: getter.ClientModeFile, + Options: opts, + } + + glog.Infof("full url: %s", urlWithChecksum) + if err := client.Get(); err != nil { + return errors.Wrap(err, isoURL) + } + return os.Rename(tmpDst, dst) +} diff --git a/pkg/minikube/preload/preload.go b/pkg/minikube/download/preload.go similarity index 60% rename from pkg/minikube/preload/preload.go rename to pkg/minikube/download/preload.go index 156542847375..05c0b4c490db 100644 --- a/pkg/minikube/preload/preload.go +++ b/pkg/minikube/download/preload.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package preload +package download import ( "context" @@ -31,15 +31,20 @@ import ( "github.com/golang/glog" "github.com/hashicorp/go-getter" "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/util" +) + +const ( + // PreloadVersion is the current version of the preloaded tarball + PreloadVersion = "v1" + // PreloadBucket is the name of the GCS bucket where preloaded volume tarballs exist + PreloadBucket = "minikube-preloaded-volume-tarballs" ) // returns name of the tarball func tarballName(k8sVersion string) string { - return fmt.Sprintf("preloaded-images-k8s-%s-%s-docker-overlay2.tar.lz4", Version, k8sVersion) + return fmt.Sprintf("preloaded-images-k8s-%s-%s-docker-overlay2.tar.lz4", PreloadVersion, k8sVersion) } // returns the name of the checksum file @@ -52,48 +57,69 @@ func targetDir() string { return localpath.MakeMiniPath("cache", "preloaded-tarball") } -// ChecksumFilepath returns path to checksum file -func ChecksumFilepath(k8sVersion string) string { +// PreloadChecksumPath returns path to checksum file +func PreloadChecksumPath(k8sVersion string) string { return path.Join(targetDir(), checksumName(k8sVersion)) } -// TarballFilepath returns the path to the preloaded tarball -func TarballFilepath(k8sVersion string) string { +// TarballPath returns the path to the preloaded tarball +func TarballPath(k8sVersion string) string { return path.Join(targetDir(), tarballName(k8sVersion)) } // remoteTarballURL returns the URL for the remote tarball in GCS func remoteTarballURL(k8sVersion string) string { - return fmt.Sprintf("https://storage.googleapis.com/%s/%s", constants.PreloadedVolumeTarballsBucket, tarballName(k8sVersion)) + return fmt.Sprintf("https://storage.googleapis.com/%s/%s", PreloadBucket, tarballName(k8sVersion)) } -// TarballExists returns true if there is a preloaded tarball -// that can be used -func TarballExists(k8sVersion, containerRuntime string) bool { +// PreloadExists returns true if there is a preloaded tarball that can be used +func PreloadExists(k8sVersion, containerRuntime string) bool { if containerRuntime != "docker" { return false } + + // Omit remote check if tarball exists locally + targetPath := TarballPath(k8sVersion) + if _, err := os.Stat(targetPath); err == nil { + if err := verifyChecksum(k8sVersion); err == nil { + glog.Infof("Found %s in cache, no need to check remotely", targetPath) + return true + } + } + url := remoteTarballURL(k8sVersion) - _, err := http.Head(url) - return err == nil + resp, err := http.Head(url) + if err != nil { + glog.Warningf("%s fetch error: %v", url, err) + return false + } + + // note: err won't be set if it's a 404 + if resp.StatusCode != 200 { + glog.Warningf("%s status code: %d", url, resp.StatusCode) + return false + } + + glog.Infof("Goody! %s exists!", url) + return true } -// CacheTarball caches the preloaded images tarball on the host machine -func CacheTarball(k8sVersion, containerRuntime string) error { +// Preload caches the preloaded images tarball on the host machine +func Preload(k8sVersion, containerRuntime string) error { if containerRuntime != "docker" { return nil } - targetFilepath := TarballFilepath(k8sVersion) + targetPath := TarballPath(k8sVersion) - if _, err := os.Stat(targetFilepath); err == nil { + if _, err := os.Stat(targetPath); err == nil { if err := verifyChecksum(k8sVersion); err == nil { - glog.Infof("Found %s in cache, skipping downloading", targetFilepath) + glog.Infof("Found %s in cache, skipping downloading", targetPath) return nil } } // Make sure we support this k8s version - if !TarballExists(k8sVersion, containerRuntime) { + if !PreloadExists(k8sVersion, containerRuntime) { glog.Infof("Preloaded tarball for k8s version %s does not exist", k8sVersion) return nil } @@ -102,9 +128,9 @@ func CacheTarball(k8sVersion, containerRuntime string) error { url := remoteTarballURL(k8sVersion) client := &getter.Client{ Src: url, - Dst: targetFilepath, + Dst: targetPath, Mode: getter.ClientModeFile, - Options: []getter.ClientOption{getter.WithProgress(util.DefaultProgressBar)}, + Options: []getter.ClientOption{getter.WithProgress(DefaultProgressBar)}, } glog.Infof("Downloading: %+v", client) @@ -112,7 +138,7 @@ func CacheTarball(k8sVersion, containerRuntime string) error { return errors.Wrapf(err, "download failed: %s", url) } // Give downloaded drivers a baseline decent file permission - if err := os.Chmod(targetFilepath, 0755); err != nil { + if err := os.Chmod(targetPath, 0755); err != nil { return err } // Save checksum file locally @@ -128,32 +154,32 @@ func saveChecksumFile(k8sVersion string) error { if err != nil { return errors.Wrap(err, "getting storage client") } - attrs, err := client.Bucket(constants.PreloadedVolumeTarballsBucket).Object(tarballName(k8sVersion)).Attrs(ctx) + attrs, err := client.Bucket(PreloadBucket).Object(tarballName(k8sVersion)).Attrs(ctx) if err != nil { return errors.Wrap(err, "getting storage object") } checksum := attrs.MD5 - return ioutil.WriteFile(ChecksumFilepath(k8sVersion), checksum, 0644) + return ioutil.WriteFile(PreloadChecksumPath(k8sVersion), checksum, 0644) } // verifyChecksum returns true if the checksum of the local binary matches // the checksum of the remote binary func verifyChecksum(k8sVersion string) error { // get md5 checksum of tarball path - contents, err := ioutil.ReadFile(TarballFilepath(k8sVersion)) + contents, err := ioutil.ReadFile(TarballPath(k8sVersion)) if err != nil { return errors.Wrap(err, "reading tarball") } checksum := md5.Sum(contents) - remoteChecksum, err := ioutil.ReadFile(ChecksumFilepath(k8sVersion)) + remoteChecksum, err := ioutil.ReadFile(PreloadChecksumPath(k8sVersion)) if err != nil { return errors.Wrap(err, "reading checksum file") } // create a slice of checksum, which is [16]byte if string(remoteChecksum) != string(checksum[:]) { - return fmt.Errorf("checksum of %s does not match remote checksum (%s != %s)", TarballFilepath(k8sVersion), string(remoteChecksum), string(checksum[:])) + return fmt.Errorf("checksum of %s does not match remote checksum (%s != %s)", TarballPath(k8sVersion), string(remoteChecksum), string(checksum[:])) } return nil } diff --git a/pkg/util/progressbar.go b/pkg/minikube/download/progressbar.go similarity index 99% rename from pkg/util/progressbar.go rename to pkg/minikube/download/progressbar.go index fb16f6773ce6..6995855b6883 100644 --- a/pkg/util/progressbar.go +++ b/pkg/minikube/download/progressbar.go @@ -18,7 +18,7 @@ limitations under the License. // based on: // https://github.com/hashicorp/go-getter/blob/master/cmd/go-getter/progress_tracking.go -package util +package download import ( "io" diff --git a/pkg/minikube/driver/install.go b/pkg/minikube/driver/install.go index 8a49e833faed..ae17a917cdba 100644 --- a/pkg/minikube/driver/install.go +++ b/pkg/minikube/driver/install.go @@ -27,12 +27,11 @@ import ( "github.com/blang/semver" "github.com/golang/glog" - "github.com/hashicorp/go-getter" "github.com/juju/mutex" "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/util/lock" ) @@ -59,7 +58,7 @@ func InstallOrUpdate(name string, directory string, v semver.Version, interactiv if !exists || (err != nil && autoUpdate) { glog.Warningf("%s: %v", executable, err) path = filepath.Join(directory, executable) - derr := download(executable, path, v) + derr := download.Driver(executable, path, v) if derr != nil { return derr } @@ -139,31 +138,6 @@ func validateDriver(executable string, v semver.Version) (string, error) { return path, nil } -func driverWithChecksumURL(name string, v semver.Version) string { - base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, name) - return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base) -} - -// download an arbitrary driver -func download(name string, destination string, v semver.Version) error { - out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": name}) - os.Remove(destination) - url := driverWithChecksumURL(name, v) - client := &getter.Client{ - Src: url, - Dst: destination, - Mode: getter.ClientModeFile, - Options: []getter.ClientOption{getter.WithProgress(util.DefaultProgressBar)}, - } - - glog.Infof("Downloading: %+v", client) - if err := client.Get(); err != nil { - return errors.Wrapf(err, "download failed: %s", url) - } - // Give downloaded drivers a baseline decent file permission - return os.Chmod(destination, 0755) -} - // extractDriverVersion extracts the driver version. // KVM and Hyperkit drivers support the 'version' command, that display the information as: // version: vX.X.X diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 898540eab388..3bb9d4d998da 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -17,22 +17,15 @@ limitations under the License. package machine import ( - "crypto" - "fmt" - "os" "path" "runtime" - "github.com/blang/semver" - "github.com/golang/glog" - "github.com/jimmidyson/go-download" "github.com/pkg/errors" "golang.org/x/sync/errgroup" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/download" ) // CacheBinariesForBootstrapper will cache binaries for a bootstrapper @@ -43,7 +36,7 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er for _, bin := range binaries { bin := bin // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { - if _, err := CacheBinary(bin, version, "linux", runtime.GOARCH); err != nil { + if _, err := download.Binary(bin, version, "linux", runtime.GOARCH); err != nil { return errors.Wrapf(err, "caching binary %s", bin) } return nil @@ -52,73 +45,6 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er return g.Wait() } -// releaseURL gets the location of a Kubernetes binary -func releaseURL(binaryName, version, osName, archName string) string { - return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) -} - -// downloadOptions returns appropriate download options for a -func downloadOptions(url string, version string) (download.FileOptions, error) { - fo := download.FileOptions{ - Mkdirs: download.MkdirAll, - Options: download.Options{ - ChecksumHash: crypto.SHA1, - Checksum: url + ".sha1", - }, - } - - v, err := semver.Make(version[1:]) - if err != nil { - return fo, err - } - - if v.GTE(semver.MustParse("1.17.0")) { - fo.ChecksumHash = crypto.SHA256 - fo.Checksum = url + ".sha256" - } - return fo, nil -} - -// CacheBinary will cache a binary on the host -func CacheBinary(binary, version, osName, archName string) (string, error) { - - targetDir := localpath.MakeMiniPath("cache", osName, version) - targetFilepath := path.Join(targetDir, binary) - - url := releaseURL(binary, version, osName, archName) - - _, err := os.Stat(targetFilepath) - // If it exists, do no verification and continue - if err == nil { - glog.Infof("Not caching binary, using %s", url) - return targetFilepath, nil - } - if !os.IsNotExist(err) { - return "", errors.Wrapf(err, "stat %s version %s at %s", binary, version, targetDir) - } - - if err = os.MkdirAll(targetDir, 0777); err != nil { - return "", errors.Wrapf(err, "mkdir %s", targetDir) - } - - options, err := downloadOptions(url, version) - if err != nil { - return "", errors.Wrap(err, "options") - } - glog.Infof("Downloading %s: options: %+v", url, options) - - out.T(out.FileDownload, "Downloading {{.name}} {{.version}}", out.V{"name": binary, "version": version}) - if err := download.ToFile(url, targetFilepath, options); err != nil { - return "", errors.Wrapf(err, url) - } - if osName == runtime.GOOS && archName == runtime.GOARCH { - if err = os.Chmod(targetFilepath, 0755); err != nil { - return "", errors.Wrapf(err, "chmod +x %s", targetFilepath) - } - } - return targetFilepath, nil -} - // CopyBinary copies a locally cached binary to the guest VM func CopyBinary(cr command.Runner, src string, dest string) error { f, err := assets.NewFileAsset(src, path.Dir(dest), path.Base(dest), "0755") diff --git a/pkg/minikube/machine/cache_binaries_test.go b/pkg/minikube/machine/cache_binaries_test.go index b490974eac1e..500c0ea74daf 100644 --- a/pkg/minikube/machine/cache_binaries_test.go +++ b/pkg/minikube/machine/cache_binaries_test.go @@ -17,15 +17,11 @@ limitations under the License. package machine import ( - "crypto" "fmt" "io/ioutil" "os" - "runtime" "testing" - "github.com/google/go-cmp/cmp" - "github.com/jimmidyson/go-download" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" @@ -126,149 +122,3 @@ func TestCacheBinariesForBootstrapper(t *testing.T) { }) } } -func TestCacheBinary(t *testing.T) { - oldMinikubeHome := os.Getenv("MINIKUBE_HOME") - defer os.Setenv("MINIKUBE_HOME", oldMinikubeHome) - - minikubeHome, err := ioutil.TempDir("/tmp", "") - if err != nil { - t.Fatalf("error during creating tmp dir: %v", err) - } - defer os.RemoveAll(minikubeHome) - noWritePermDir, err := ioutil.TempDir("/tmp", "") - if err != nil { - t.Fatalf("error during creating tmp dir: %v", err) - } - defer os.RemoveAll(noWritePermDir) - err = os.Chmod(noWritePermDir, 0000) - if err != nil { - t.Fatalf("error (%v) during changing permissions of dir %v", err, noWritePermDir) - } - - var tc = []struct { - desc, version, osName, archName string - minikubeHome, binary, description string - err bool - }{ - { - desc: "ok kubeadm", - version: "v1.16.0", - osName: "linux", - archName: runtime.GOARCH, - binary: "kubeadm", - err: false, - minikubeHome: minikubeHome, - }, - { - desc: "minikube home in dir without perms and arm runtime", - version: "v1.16.0", - osName: runtime.GOOS, - archName: "arm", - binary: "kubectl", - err: true, - minikubeHome: noWritePermDir, - }, - { - desc: "minikube home in dir without perms", - version: "v1.16.0", - osName: runtime.GOOS, - archName: runtime.GOARCH, - binary: "kubectl", - err: true, - minikubeHome: noWritePermDir, - }, - { - desc: "binary foo", - version: "v1.16.0", - osName: runtime.GOOS, - archName: runtime.GOARCH, - binary: "foo", - err: true, - minikubeHome: minikubeHome, - }, - { - desc: "version 9000", - version: "v9000", - osName: runtime.GOOS, - archName: runtime.GOARCH, - binary: "foo", - err: true, - minikubeHome: minikubeHome, - }, - { - desc: "bad os", - version: "v1.16.0", - osName: "no-such-os", - archName: runtime.GOARCH, - binary: "kubectl", - err: true, - minikubeHome: minikubeHome, - }, - } - for _, test := range tc { - t.Run(test.desc, func(t *testing.T) { - os.Setenv("MINIKUBE_HOME", test.minikubeHome) - _, err := CacheBinary(test.binary, test.version, test.osName, test.archName) - if err != nil && !test.err { - t.Fatalf("Got unexpected error %v", err) - } - if err == nil && test.err { - t.Fatalf("Expected error but got %v", err) - } - }) - } -} - -func TestDownloadOptions(t *testing.T) { - var tc = []struct { - url string - version string - want download.FileOptions - }{ - { - url: "https://s/kubernetes-release/release/v1.16.0/bin/amd64/kubectl", - version: "v1.16.0", - want: download.FileOptions{ - Options: download.Options{ - Checksum: "https://s/kubernetes-release/release/v1.16.0/bin/amd64/kubectl.sha1", - ChecksumHash: crypto.SHA1, - }, - Mkdirs: download.MkdirAll, - }, - }, - { - url: "https://s/kubernetes-release/release/v1.10.0/bin/hp9k/kubeadm", - version: "v1.10.0", - want: download.FileOptions{ - Options: download.Options{ - Checksum: "https://s/kubernetes-release/release/v1.10.0/bin/hp9k/kubeadm.sha1", - ChecksumHash: crypto.SHA1, - }, - Mkdirs: download.MkdirAll, - }, - }, - { - url: "https://s/kubernetes-release/release/v1.18.0/bin/arm64/kubelet", - version: "v1.18.0", - want: download.FileOptions{ - Options: download.Options{ - Checksum: "https://s/kubernetes-release/release/v1.18.0/bin/arm64/kubelet.sha256", - ChecksumHash: crypto.SHA256, - }, - Mkdirs: download.MkdirAll, - }, - }, - } - for _, test := range tc { - t.Run(test.version, func(t *testing.T) { - got, err := downloadOptions(test.url, test.version) - if err != nil { - t.Fatalf("unexpected error %v", err) - } - - if diff := cmp.Diff(test.want, got); diff != "" { - t.Errorf("unexpected options(-want +got):\n%s", diff) - } - }) - } -} diff --git a/pkg/minikube/machine/cluster_test.go b/pkg/minikube/machine/cluster_test.go index b197cf92dff9..114f8b023a16 100644 --- a/pkg/minikube/machine/cluster_test.go +++ b/pkg/minikube/machine/cluster_test.go @@ -30,17 +30,11 @@ import ( "github.com/docker/machine/libmachine/state" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/registry" "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 } - func createMockDriverHost(c config.ClusterConfig, n config.Node) (interface{}, error) { return nil, nil } @@ -61,12 +55,10 @@ func RegisterMockDriver(t *testing.T) { } var defaultClusterConfig = config.ClusterConfig{ - Name: viper.GetString("profile"), - Driver: driver.Mock, - MinikubeISO: constants.DefaultISOURL, - Downloader: MockDownloader{}, - DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"}, - Nodes: []config.Node{config.Node{Name: "minikube"}}, + Name: viper.GetString("profile"), + Driver: driver.Mock, + DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"}, + Nodes: []config.Node{config.Node{Name: "minikube"}}, } func TestCreateHost(t *testing.T) { @@ -271,10 +263,9 @@ func TestStartHostConfig(t *testing.T) { provision.SetDetector(md) cfg := config.ClusterConfig{ - Driver: driver.Mock, - DockerEnv: []string{"FOO=BAR"}, - DockerOpt: []string{"param=value"}, - Downloader: MockDownloader{}, + Driver: driver.Mock, + DockerEnv: []string{"FOO=BAR"}, + DockerOpt: []string{"param=value"}, } h, err := StartHost(api, cfg, config.Node{Name: "minikube"}) diff --git a/pkg/minikube/node/cache.go b/pkg/minikube/node/cache.go index fce265bf7764..67bf646ce747 100644 --- a/pkg/minikube/node/cache.go +++ b/pkg/minikube/node/cache.go @@ -27,16 +27,16 @@ import ( "k8s.io/minikube/pkg/drivers/kic" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/image" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/minikube/preload" ) -// beginCacheRequiredImages caches images required for kubernetes version in the background -func beginCacheRequiredImages(g *errgroup.Group, imageRepository string, k8sVersion string) { +// beginCacheKubernetesImages caches images required for kubernetes version in the background +func beginCacheKubernetesImages(g *errgroup.Group, imageRepository string, k8sVersion string) { if !viper.GetBool("cache-images") { return } @@ -74,7 +74,7 @@ func CacheKubectlBinary(k8sVerison string) (string, error) { binary = "kubectl.exe" } - return machine.CacheBinary(binary, k8sVerison, runtime.GOOS, runtime.GOARCH) + return download.Binary(binary, k8sVerison, runtime.GOOS, runtime.GOARCH) } // doCacheBinaries caches Kubernetes binaries in the foreground @@ -82,22 +82,28 @@ func doCacheBinaries(k8sVersion string) error { return machine.CacheBinariesForBootstrapper(k8sVersion, viper.GetString(cmdcfg.Bootstrapper)) } -func beginDownloadKicArtifacts(g *errgroup.Group, k8sVersion, cRuntime string) { +// beginDownloadKicArtifacts downloads the kic image + preload tarball, returns true if preload is available +func beginDownloadKicArtifacts(g *errgroup.Group, k8sVersion, cRuntime string) bool { glog.Info("Beginning downloading kic artifacts") g.Go(func() error { glog.Infof("Downloading %s to local daemon", kic.BaseImage) return image.WriteImageToDaemon(kic.BaseImage) }) - g.Go(func() error { - glog.Info("Caching tarball of preloaded images") - return preload.CacheTarball(k8sVersion, cRuntime) - }) + if download.PreloadExists(k8sVersion, cRuntime) { + g.Go(func() error { + glog.Info("Caching tarball of preloaded images") + return download.Preload(k8sVersion, cRuntime) + }) + return true + } + return false } func waitDownloadKicArtifacts(g *errgroup.Group) { if err := g.Wait(); err != nil { glog.Errorln("Error downloading kic artifacts: ", err) + return } glog.Info("Successfully downloaded all kic artifacts") } diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index 19eb4d511229..44a1667c469f 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -29,7 +29,6 @@ import ( "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/logs" "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/minikube/preload" "k8s.io/minikube/pkg/util" ) @@ -41,14 +40,17 @@ func Start(mc config.ClusterConfig, n config.Node, primary bool, existingAddons // See if we can create a volume of preloaded images // If not, pull images in the background while the VM boots. var kicGroup errgroup.Group + needKubernetesImages := true if driver.IsKIC(driverName) { - beginDownloadKicArtifacts(&kicGroup, k8sVersion, mc.KubernetesConfig.ContainerRuntime) + // If we can download a preload tarball, it isn't necessary to pull Kubernetes images + if beginDownloadKicArtifacts(&kicGroup, k8sVersion, mc.KubernetesConfig.ContainerRuntime) { + needKubernetesImages = false + } } - // Now that the ISO is downloaded, pull images in the background while the VM boots. + var cacheGroup errgroup.Group - skipCacheImages := driver.IsKIC(driverName) && preload.TarballExists(k8sVersion, mc.KubernetesConfig.ContainerRuntime) - if !skipCacheImages { - beginCacheRequiredImages(&cacheGroup, mc.KubernetesConfig.ImageRepository, k8sVersion) + if needKubernetesImages { + beginCacheKubernetesImages(&cacheGroup, mc.KubernetesConfig.ImageRepository, k8sVersion) } // Abstraction leakage alert: startHost requires the config to be saved, to satistfy pkg/provision/buildroot. diff --git a/pkg/minikube/preload/constants.go b/pkg/minikube/preload/constants.go deleted file mode 100644 index ca09325e37e6..000000000000 --- a/pkg/minikube/preload/constants.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2020 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 preload - -const ( - // Version is the current version of the preloaded tarball - Version = "v1" -) diff --git a/pkg/minikube/registry/drvs/hyperkit/hyperkit.go b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go index 8280b4811f47..43ce54b6b61a 100644 --- a/pkg/minikube/registry/drvs/hyperkit/hyperkit.go +++ b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go @@ -32,6 +32,7 @@ import ( "k8s.io/minikube/pkg/drivers/hyperkit" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -69,7 +70,7 @@ func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { StorePath: localpath.MiniPath(), SSHUser: "docker", }, - Boot2DockerURL: cfg.Downloader.GetISOFileURI(cfg.MinikubeISO), + Boot2DockerURL: download.LocalISOResource(cfg.MinikubeISO), DiskSize: cfg.DiskSize, Memory: cfg.Memory, CPU: cfg.CPUs, diff --git a/pkg/minikube/registry/drvs/hyperv/hyperv.go b/pkg/minikube/registry/drvs/hyperv/hyperv.go index 02161a62ddcd..2c6c6603908f 100644 --- a/pkg/minikube/registry/drvs/hyperv/hyperv.go +++ b/pkg/minikube/registry/drvs/hyperv/hyperv.go @@ -30,6 +30,7 @@ import ( "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -54,7 +55,7 @@ func init() { func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { d := hyperv.NewDriver(driver.MachineName(cfg, n), localpath.MiniPath()) - d.Boot2DockerURL = cfg.Downloader.GetISOFileURI(cfg.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(cfg.MinikubeISO) d.VSwitch = cfg.HypervVirtualSwitch if d.VSwitch == "" && cfg.HypervUseExternalSwitch { switchName, adapter, err := chooseSwitch(cfg.HypervExternalAdapter) diff --git a/pkg/minikube/registry/drvs/kvm2/kvm2.go b/pkg/minikube/registry/drvs/kvm2/kvm2.go index 12495f7bd998..fae105572d91 100644 --- a/pkg/minikube/registry/drvs/kvm2/kvm2.go +++ b/pkg/minikube/registry/drvs/kvm2/kvm2.go @@ -30,6 +30,7 @@ import ( "github.com/docker/machine/libmachine/drivers" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -79,7 +80,7 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { CPU: cc.CPUs, Network: cc.KVMNetwork, PrivateNetwork: "minikube-net", - Boot2DockerURL: cc.Downloader.GetISOFileURI(cc.MinikubeISO), + Boot2DockerURL: download.LocalISOResource(cc.MinikubeISO), DiskSize: cc.DiskSize, DiskPath: filepath.Join(localpath.MiniPath(), "machines", name, fmt.Sprintf("%s.rawdisk", name)), ISO: filepath.Join(localpath.MiniPath(), "machines", name, "boot2docker.iso"), diff --git a/pkg/minikube/registry/drvs/parallels/parallels.go b/pkg/minikube/registry/drvs/parallels/parallels.go index 3284cf2ed7f1..1f14bb653a58 100644 --- a/pkg/minikube/registry/drvs/parallels/parallels.go +++ b/pkg/minikube/registry/drvs/parallels/parallels.go @@ -25,6 +25,7 @@ import ( parallels "github.com/Parallels/docker-machine-parallels" "github.com/docker/machine/libmachine/drivers" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -46,7 +47,7 @@ func init() { func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { d := parallels.NewDriver(driver.MachineName(cfg, n), localpath.MiniPath()).(*parallels.Driver) - d.Boot2DockerURL = cfg.Downloader.GetISOFileURI(cfg.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(cfg.MinikubeISO) d.Memory = cfg.Memory d.CPU = cfg.CPUs d.DiskSize = cfg.DiskSize diff --git a/pkg/minikube/registry/drvs/virtualbox/virtualbox.go b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go index 713e5a3f0aad..0bc784b5d2bf 100644 --- a/pkg/minikube/registry/drvs/virtualbox/virtualbox.go +++ b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go @@ -27,6 +27,7 @@ import ( "github.com/docker/machine/libmachine/drivers" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -51,7 +52,7 @@ func init() { func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { d := virtualbox.NewDriver(driver.MachineName(cc, n), localpath.MiniPath()) - d.Boot2DockerURL = cc.Downloader.GetISOFileURI(cc.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(cc.MinikubeISO) d.Memory = cc.Memory d.CPU = cc.CPUs d.DiskSize = cc.DiskSize diff --git a/pkg/minikube/registry/drvs/vmware/vmware.go b/pkg/minikube/registry/drvs/vmware/vmware.go index 69270b98ea62..c6e5e0d684a8 100644 --- a/pkg/minikube/registry/drvs/vmware/vmware.go +++ b/pkg/minikube/registry/drvs/vmware/vmware.go @@ -22,6 +22,7 @@ import ( vmwcfg "github.com/machine-drivers/docker-machine-driver-vmware/pkg/drivers/vmware/config" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -41,7 +42,7 @@ func init() { func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { d := vmwcfg.NewConfig(driver.MachineName(cc, n), localpath.MiniPath()) - d.Boot2DockerURL = cc.Downloader.GetISOFileURI(cc.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(cc.MinikubeISO) d.Memory = cc.Memory d.CPU = cc.CPUs d.DiskSize = cc.DiskSize diff --git a/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go index af0e0b7eb410..b571113941be 100644 --- a/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go +++ b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go @@ -27,6 +27,7 @@ import ( "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -46,7 +47,7 @@ func init() { func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { d := vmwarefusion.NewDriver(driver.MachineName(cfg, n), localpath.MiniPath()).(*vmwarefusion.Driver) - d.Boot2DockerURL = cfg.Downloader.GetISOFileURI(cfg.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(cfg.MinikubeISO) d.Memory = cfg.Memory d.CPU = cfg.CPUs d.DiskSize = cfg.DiskSize diff --git a/pkg/util/downloader.go b/pkg/util/downloader.go deleted file mode 100644 index 72b478256589..000000000000 --- a/pkg/util/downloader.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -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 ( - "net/url" - "os" - "path/filepath" - "time" - - "github.com/golang/glog" - "github.com/hashicorp/go-getter" - "github.com/juju/mutex" - "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/util/lock" -) - -const fileScheme = "file" - -// ISODownloader downloads an ISO -type ISODownloader interface { - GetISOFileURI(isoURL string) string - CacheMinikubeISOFromURL(isoURL string) error -} - -// DefaultDownloader is the default ISODownloader -type DefaultDownloader struct{} - -// GetISOFileURI gets the local destination for a remote source -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(localpath.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) -} - -// CacheMinikubeISOFromURL downloads the ISO, if it doesn't exist in cache -func (f DefaultDownloader) CacheMinikubeISOFromURL(url string) error { - dst := f.GetISOCacheFilepath(url) - - // Lock before we check for existence to avoid thundering herd issues - spec := lock.PathMutexSpec(dst) - spec.Timeout = 10 * time.Minute - glog.Infof("acquiring lock: %+v", spec) - releaser, err := mutex.Acquire(spec) - if err != nil { - return errors.Wrapf(err, "unable to acquire lock for %+v", spec) - } - defer releaser.Release() - - if !f.ShouldCacheMinikubeISO(url) { - glog.Infof("Not caching ISO, using %s", url) - return nil - } - - urlWithChecksum := url - if url == constants.DefaultISOURL { - urlWithChecksum = url + "?checksum=file:" + constants.DefaultISOSHAURL - } - - // Predictable temp destination so that resume can function - tmpDst := dst + ".download" - - opts := []getter.ClientOption{getter.WithProgress(DefaultProgressBar)} - client := &getter.Client{ - Src: urlWithChecksum, - Dst: tmpDst, - Mode: getter.ClientModeFile, - Options: opts, - } - - glog.Infof("full url: %s", urlWithChecksum) - out.T(out.ISODownload, "Downloading VM boot image ...") - if err := client.Get(); err != nil { - return errors.Wrap(err, url) - } - return os.Rename(tmpDst, dst) -} - -// ShouldCacheMinikubeISO returns if we need to download the ISO -func (f DefaultDownloader) ShouldCacheMinikubeISO(isoURL string) bool { - // store the minikube-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 -} - -// GetISOCacheFilepath returns the path of an ISO in the local cache -func (f DefaultDownloader) GetISOCacheFilepath(isoURL string) string { - return filepath.Join(localpath.MiniPath(), "cache", "iso", filepath.Base(isoURL)) -} - -// IsMinikubeISOCached returns if an ISO exists in the local cache -func (f DefaultDownloader) IsMinikubeISOCached(isoURL string) bool { - if _, err := os.Stat(f.GetISOCacheFilepath(isoURL)); os.IsNotExist(err) { - return false - } - return true -} diff --git a/pkg/util/downloader_test.go b/pkg/util/downloader_test.go deleted file mode 100644 index 3db859329697..000000000000 --- a/pkg/util/downloader_test.go +++ /dev/null @@ -1,117 +0,0 @@ -/* -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 ( - "bytes" - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "testing" - - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/tests" -) - -func TestGetISOFileURI(t *testing.T) { - dler := DefaultDownloader{} - - tests := map[string]string{ - "file:///test/path/minikube-test.iso": "file:///test/path/minikube-test.iso", - "https://storage.googleapis.com/minikube/iso/minikube-test.iso": "file://" + filepath.ToSlash(filepath.Join(localpath.MiniPath(), "cache", "iso", "minikube-test.iso")), - } - - for input, expected := range tests { - if isoFileURI := dler.GetISOFileURI(input); isoFileURI != expected { - t.Fatalf("Expected GetISOFileURI with input %s to return %s but instead got: %s", input, expected, isoFileURI) - } - } - -} - -var testISOString = "hello" - -func TestCacheMinikubeISOFromURL(t *testing.T) { - tempDir := tests.MakeTempDir() - defer os.RemoveAll(tempDir) - dler := DefaultDownloader{} - isoPath := filepath.Join(localpath.MiniPath(), "cache", "iso", "minikube-test.iso") - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if _, err := io.WriteString(w, testISOString); err != nil { - t.Fatalf("WriteString: %v", err) - } - })) - isoURL := server.URL + "/minikube-test.iso" - if err := dler.CacheMinikubeISOFromURL(isoURL); err != nil { - t.Fatalf("Unexpected error from CacheMinikubeISOFromURL: %v", err) - } - - transferred, err := ioutil.ReadFile(filepath.Join(isoPath)) - if err != nil { - t.Fatalf("File not copied. Could not open file at path: %s", isoPath) - } - - // test that the ISO is transferred properly - contents := []byte(testISOString) - if !bytes.Contains(transferred, contents) { - t.Fatalf("Expected transfers to contain: %s. It was: %s", contents, transferred) - } - -} - -func TestShouldCacheMinikubeISO(t *testing.T) { - dler := DefaultDownloader{} - - tests := map[string]bool{ - "file:///test/path/minikube-test.iso": false, - "https://storage.googleapis.com/minikube/iso/minikube-test.iso": true, - } - - for input, expected := range tests { - if out := dler.ShouldCacheMinikubeISO(input); out != expected { - t.Fatalf("Expected ShouldCacheMinikubeISO with input %s to return %t but instead got: %t", input, expected, out) - } - } -} - -func TestIsMinikubeISOCached(t *testing.T) { - tempDir := tests.MakeTempDir() - defer os.RemoveAll(tempDir) - - dler := DefaultDownloader{} - - testFileURI := "file:///test/path/minikube-test.iso" - expected := false - - if out := dler.IsMinikubeISOCached(testFileURI); out != expected { - t.Fatalf("Expected IsMinikubeISOCached with input %s to return %t but instead got: %t", testFileURI, expected, out) - } - - if err := ioutil.WriteFile(filepath.Join(localpath.MiniPath(), "cache", "iso", "minikube-test.iso"), []byte(testISOString), os.FileMode(int(0644))); err != nil { - t.Fatalf("WriteFile: %v", err) - } - - expected = true - if out := dler.IsMinikubeISOCached(testFileURI); out != expected { - t.Fatalf("Expected IsMinikubeISOCached with input %s to return %t but instead got: %t", testFileURI, expected, out) - } - -} diff --git a/pkg/version/version.go b/pkg/version/version.go index 727035115b1b..a3b921c5caae 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -25,8 +25,6 @@ import ( // VersionPrefix is the prefix of the git tag for a version const VersionPrefix = "v" -// The current version of the minikube - // version is a private field and should be set when compiling with --ldflags="-X k8s.io/minikube/pkg/version.version=vX.Y.Z" var version = "v0.0.0-unset" @@ -36,8 +34,6 @@ var gitCommitID = "" // isoVersion is a private field and should be set when compiling with --ldflags="-X k8s.io/minikube/pkg/version.isoVersion=vX.Y.Z" var isoVersion = "v0.0.0-unset" -var isoPath = "minikube/iso" - // GetVersion returns the current minikube version func GetVersion() string { return version @@ -53,11 +49,6 @@ func GetISOVersion() string { return isoVersion } -// GetISOPath returns the remote path to the minikube.iso -func GetISOPath() string { - return isoPath -} - // GetSemverVersion returns the current minikube semantic version (semver) func GetSemverVersion() (semver.Version, error) { return semver.Make(strings.TrimPrefix(GetVersion(), VersionPrefix)) diff --git a/site/content/en/docs/Contributing/drivers.en.md b/site/content/en/docs/Contributing/drivers.en.md index 527555e53318..c1dd9372c3a6 100644 --- a/site/content/en/docs/Contributing/drivers.en.md +++ b/site/content/en/docs/Contributing/drivers.en.md @@ -87,7 +87,7 @@ func init() { func createVMwareFusionHost(config cfg.ClusterConfig) interface{} { d := vmwarefusion.NewDriver(config.Name, localpath.MiniPath()).(*vmwarefusion.Driver) - d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(config.MinikubeISO) d.Memory = config.Memory d.CPU = config.CPUs d.DiskSize = config.DiskSize diff --git a/test/integration/aaa_download_only_test.go b/test/integration/aaa_download_only_test.go index d64f37b58ed8..e4ca5ebb264b 100644 --- a/test/integration/aaa_download_only_test.go +++ b/test/integration/aaa_download_only_test.go @@ -38,8 +38,8 @@ import ( "k8s.io/minikube/pkg/minikube/bootstrapper/images" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/preload" ) func TestDownloadOnly(t *testing.T) { @@ -182,15 +182,15 @@ func TestDownloadOnlyDocker(t *testing.T) { t.Errorf("%s failed: %v:\n%s", args, err, rr.Output()) } - // Make sure the preloaded image tarball exists - tarball := preload.TarballFilepath(constants.DefaultKubernetesVersion) + // Make sure the downloaded image tarball exists + tarball := download.TarballPath(constants.DefaultKubernetesVersion) contents, err := ioutil.ReadFile(tarball) if err != nil { t.Errorf("reading tarball: %v", err) } // Make sure it has the correct checksum checksum := md5.Sum(contents) - remoteChecksum, err := ioutil.ReadFile(preload.ChecksumFilepath(constants.DefaultKubernetesVersion)) + remoteChecksum, err := ioutil.ReadFile(download.PreloadChecksumPath(constants.DefaultKubernetesVersion)) if err != nil { t.Errorf("reading checksum file: %v", err) }