diff --git a/cmd/minikube/cmd/cache.go b/cmd/minikube/cmd/cache.go index 86926c5d353f..7b403f4b904f 100644 --- a/cmd/minikube/cmd/cache.go +++ b/cmd/minikube/cmd/cache.go @@ -81,6 +81,18 @@ func imagesInConfigFile() ([]string, error) { return []string{}, nil } +// CacheImagesInConfigFile caches the images currently in the config file (minikube start) +func CacheImagesInConfigFile() error { + images, err := imagesInConfigFile() + if err != nil { + return err + } + if len(images) == 0 { + return nil + } + return machine.CacheImages(images, constants.ImageCacheDir) +} + // LoadCachedImagesInConfigFile loads the images currently in the config file (minikube start) func LoadCachedImagesInConfigFile() error { images, err := imagesInConfigFile() diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 8a3b56530be3..2ead8c47d1c3 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -86,6 +86,7 @@ const ( gpu = "gpu" embedCerts = "embed-certs" noVTXCheck = "no-vtx-check" + downloadOnly = "download-only" ) var ( @@ -135,6 +136,7 @@ func init() { startCmd.Flags().Bool(enableDefaultCNI, false, "Enable the default CNI plugin (/etc/cni/net.d/k8s.conf). Used in conjunction with \"--network-plugin=cni\"") startCmd.Flags().String(featureGates, "", "A set of key=value pairs that describe feature gates for alpha/experimental features.") startCmd.Flags().Bool(cacheImages, true, "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. @@ -185,6 +187,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(config.MachineConfig); err != nil { + exit.WithError("Failed to cache ISO", err) + } + if err := doCacheBinaries(k8sVersion); err != nil { + exit.WithError("Failed to cache binaries", err) + } + waitCacheImages(&cacheGroup) + if err := CacheImagesInConfigFile(); err != nil { + exit.WithError("Failed to cache images", err) + } + console.OutStyle("check", "Download complete!") + return + } + host, preexisting := startHost(m, config.MachineConfig) ip := validateNetwork(host) @@ -240,6 +258,11 @@ func validateConfig() { } } +// doCacheBinaries caches Kubernetes binaries in the foreground +func doCacheBinaries(k8sVersion string) error { + return machine.CacheBinariesForBootstrapper(k8sVersion, viper.GetString(cmdcfg.Bootstrapper)) +} + // beginCacheImages caches Docker images in the background func beginCacheImages(g *errgroup.Group, k8sVersion string) { if !viper.GetBool(cacheImages) { diff --git a/pkg/minikube/bootstrapper/bootstrapper.go b/pkg/minikube/bootstrapper/bootstrapper.go index e7d9ed4bbb85..390430a99b30 100644 --- a/pkg/minikube/bootstrapper/bootstrapper.go +++ b/pkg/minikube/bootstrapper/bootstrapper.go @@ -51,6 +51,16 @@ const ( BootstrapperTypeKubeadm = "kubeadm" ) +// GetCachedBinaryList returns the list of binaries +func GetCachedBinaryList(bootstrapper string) []string { + switch bootstrapper { + case BootstrapperTypeKubeadm: + return constants.GetKubeadmCachedBinaries() + default: + return []string{} + } +} + // GetCachedImageList returns the list of images for a version func GetCachedImageList(imageRepository string, version string, bootstrapper string) []string { switch bootstrapper { diff --git a/pkg/minikube/console/style.go b/pkg/minikube/console/style.go index 1a7f45636f29..63c11185545e 100644 --- a/pkg/minikube/console/style.go +++ b/pkg/minikube/console/style.go @@ -66,6 +66,7 @@ var styles = map[string]style{ "log-entry": {Prefix: " "}, // Indent "crushed": {Prefix: "💔 "}, "url": {Prefix: "👉 "}, + "check": {Prefix: "✔️ "}, // Specialized purpose styles "iso-download": {Prefix: "💿 ", LowPrefix: "@ "}, diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 9745f37135f2..b21c76d85a0f 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -31,6 +31,23 @@ import ( "k8s.io/minikube/pkg/minikube/constants" ) +// CacheBinariesForBootstrapper will cache binaries for a bootstrapper +func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) error { + binaries := bootstrapper.GetCachedBinaryList(clusterBootstrapper) + + var g errgroup.Group + for _, bin := range binaries { + bin := bin + g.Go(func() error { + if _, err := CacheBinary(bin, version); err != nil { + return errors.Wrapf(err, "caching image %s", bin) + } + return nil + }) + } + return g.Wait() +} + // CacheBinary will cache a binary on the host func CacheBinary(binary, version string) (string, error) { targetDir := constants.MakeMiniPath("cache", version)