Skip to content

Commit

Permalink
Add --download-only option to start command
Browse files Browse the repository at this point in the history
Make it possible to download files without loading or installing,
and without starting the host... Download: ISO, binaries, images.

Make caching into functions (making the loading part optional),
and move it from concrete bootstrapper to the abstract interface.
  • Loading branch information
afbjorklund committed Feb 22, 2019
1 parent 8cae13f commit c48493e
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 63 deletions.
8 changes: 6 additions & 2 deletions cmd/minikube/cmd/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ var deleteCacheCmd = &cobra.Command{
}

// LoadCachedImagesInConfigFile loads the images currently in the config file (minikube start)
func LoadCachedImagesInConfigFile() error {
func LoadCachedImagesInConfigFile(load bool) error {
configFile, err := config.ReadConfig()
if err != nil {
return err
Expand All @@ -77,7 +77,11 @@ func LoadCachedImagesInConfigFile() error {
for key := range values.(map[string]interface{}) {
images = append(images, key)
}
return machine.CacheAndLoadImages(images)
if load {
return machine.CacheAndLoadImages(images)
} else {
return machine.CacheImages(images, constants.ImageCacheDir)
}
}
return nil
}
Expand Down
20 changes: 19 additions & 1 deletion cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const (
vsockPorts = "hyperkit-vsock-ports"
gpu = "gpu"
embedCerts = "embed-certs"
downloadOnly = "download-only"
)

var (
Expand Down Expand Up @@ -131,6 +132,7 @@ func init() {
startCmd.Flags().String(featureGates, "", "A set of key=value pairs that describe feature gates for alpha/experimental features.")
// TODO(tstromberg): Flip cacheImages to true once it can be stabilized
startCmd.Flags().Bool(cacheImages, false, "If true, cache docker images for the current bootstrapper and load them into the machine.")
startCmd.Flags().Bool(downloadOnly, false, "If true, only download and cache files for later use - don't install or start anything.")
startCmd.Flags().Var(&extraOptions, "extra-config",
`A set of key=value pairs that describe configuration that may be passed to different components.
The key should be '.' separated, and the first part before the dot is the component to apply the configuration to.
Expand Down Expand Up @@ -180,6 +182,22 @@ func runStart(cmd *cobra.Command, args []string) {
if err != nil {
exit.WithError("Failed to get machine client", err)
}

if viper.GetBool(downloadOnly) {
if err := cluster.CacheISO(m, config.MachineConfig); err != nil {
exit.WithError("Failed to cache ISO", err)
}
if err := bootstrapper.CacheBinaries(nil, config.KubernetesConfig); err != nil {
exit.WithError("Failed to cache binaries", err)
}
waitCacheImages(&cacheGroup)
if err := LoadCachedImagesInConfigFile(false); err != nil {
exit.WithError("Failed to cache images", err)
}
console.OutStyle("check", "Download complete and in download only mode")
return
}

host, preexisting := startHost(m, config.MachineConfig)

ip := validateNetwork(host)
Expand All @@ -202,7 +220,7 @@ func runStart(cmd *cobra.Command, args []string) {
bootstrapCluster(bs, cr, runner, config.KubernetesConfig, preexisting)
validateCluster(bs, cr, runner, ip)
configureMounts()
if err = LoadCachedImagesInConfigFile(); err != nil {
if err = LoadCachedImagesInConfigFile(true); err != nil {
console.Failure("Unable to load cached images from config file.")
}

Expand Down
69 changes: 69 additions & 0 deletions pkg/minikube/bootstrapper/bootstrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@ limitations under the License.
package bootstrapper

import (
"crypto"
"net"
"os"
"path"

"github.com/golang/glog"
download "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/config"
"k8s.io/minikube/pkg/minikube/console"
"k8s.io/minikube/pkg/minikube/constants"
)

Expand Down Expand Up @@ -58,3 +67,63 @@ func GetCachedImageList(version string, bootstrapper string) []string {
return []string{}
}
}

// CacheBinaries downloads binaries that will be used by UpdateCluster
func CacheBinaries(cr CommandRunner, k8s config.KubernetesConfig) error {
var g errgroup.Group
for _, bin := range []string{"kubelet", "kubeadm"} {
bin := bin
g.Go(func() error {
path, err := maybeDownloadAndCache(bin, k8s.KubernetesVersion)
if err != nil {
return errors.Wrapf(err, "downloading %s", bin)
}
if cr == nil {
return nil
}
f, err := assets.NewFileAsset(path, "/usr/bin", bin, "0641")
if err != nil {
return errors.Wrap(err, "new file asset")
}
if err := cr.Copy(f); err != nil {
return errors.Wrapf(err, "copy")
}
return nil
})
}
return g.Wait()
}

func maybeDownloadAndCache(binary, version string) (string, error) {
targetDir := constants.MakeMiniPath("cache", version)
targetFilepath := path.Join(targetDir, binary)

url := constants.GetKubernetesReleaseURL(binary, version)

_, 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 := download.FileOptions{
Mkdirs: download.MkdirAll,
}

options.Checksum = constants.GetKubernetesReleaseURLSha1(binary, version)
options.ChecksumHash = crypto.SHA1

console.OutStyle("file-download", "Downloading %s %s", binary, version)
if err := download.ToFile(url, targetFilepath, options); err != nil {
return "", errors.Wrapf(err, "Error downloading %s %s", binary, version)
}
return targetFilepath, nil
}
57 changes: 1 addition & 56 deletions pkg/minikube/bootstrapper/kubeadm/kubeadm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,18 @@ package kubeadm

import (
"bytes"
"crypto"
"crypto/tls"
"fmt"
"net"
"net/http"
"os"
"path"
"strings"
"time"

"github.com/blang/semver"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
download "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/config"
Expand Down Expand Up @@ -348,25 +343,7 @@ func (k *KubeadmBootstrapper) UpdateCluster(cfg config.KubernetesConfig) error {
assets.NewMemoryAssetTarget([]byte(defaultCNIConfig), constants.DefaultRktNetConfigPath, "0644"))
}

var g errgroup.Group
for _, bin := range []string{"kubelet", "kubeadm"} {
bin := bin
g.Go(func() error {
path, err := maybeDownloadAndCache(bin, cfg.KubernetesVersion)
if err != nil {
return errors.Wrapf(err, "downloading %s", bin)
}
f, err := assets.NewFileAsset(path, "/usr/bin", bin, "0641")
if err != nil {
return errors.Wrap(err, "new file asset")
}
if err := k.c.Copy(f); err != nil {
return errors.Wrapf(err, "copy")
}
return nil
})
}
if err := g.Wait(); err != nil {
if err := bootstrapper.CacheBinaries(k.c, cfg); err != nil {
return errors.Wrap(err, "downloading binaries")
}

Expand Down Expand Up @@ -460,35 +437,3 @@ func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) (string, er

return b.String(), nil
}

func maybeDownloadAndCache(binary, version string) (string, error) {
targetDir := constants.MakeMiniPath("cache", version)
targetFilepath := path.Join(targetDir, binary)

_, err := os.Stat(targetFilepath)
// If it exists, do no verification and continue
if err == nil {
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)
}

url := constants.GetKubernetesReleaseURL(binary, version)
options := download.FileOptions{
Mkdirs: download.MkdirAll,
}

options.Checksum = constants.GetKubernetesReleaseURLSha1(binary, version)
options.ChecksumHash = crypto.SHA1

console.OutStyle("file-download", "Downloading %s %s", binary, version)
if err := download.ToFile(url, targetFilepath, options); err != nil {
return "", errors.Wrapf(err, "Error downloading %s %s", binary, version)
}
return targetFilepath, nil
}
17 changes: 13 additions & 4 deletions pkg/minikube/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ func init() {
ssh.SetDefaultClient(ssh.Native)
}

// CacheISO downloads and caches ISO.
func CacheISO(api libmachine.API, config cfg.MachineConfig) error {
if config.VMDriver != "none" {
if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil {
return err
}
}
return nil
}

// StartHost starts a host VM.
func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) {
exists, err := api.Exists(cfg.GetMachineName())
Expand Down Expand Up @@ -282,10 +292,9 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
exit.WithError("error getting driver", err)
}

if config.VMDriver != "none" {
if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil {
return nil, errors.Wrap(err, "unable to cache ISO")
}
err = CacheISO(api, config)
if err != nil {
return nil, errors.Wrap(err, "unable to cache ISO")
}

driver := def.ConfigCreator(config)
Expand Down
1 change: 1 addition & 0 deletions pkg/minikube/console/style.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ var styles = map[string]style{
"log-entry": {Prefix: " "}, // Indent
"crushed": {Prefix: "💔 "},
"url": {Prefix: "👉 "},
"check": {Prefix: "✔️ "},

// Specialized purpose styles
"iso-download": {Prefix: "💿 ", LowPrefix: "@ "},
Expand Down

0 comments on commit c48493e

Please sign in to comment.