diff --git a/cmd/minikube/cmd/cache.go b/cmd/minikube/cmd/cache.go index 8114ae73a300..65b16f5ab584 100644 --- a/cmd/minikube/cmd/cache.go +++ b/cmd/minikube/cmd/cache.go @@ -20,11 +20,9 @@ import ( "fmt" "github.com/spf13/cobra" cmdConfig "k8s.io/minikube/cmd/minikube/cmd/config" - "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/machine" - "k8s.io/minikube/pkg/minikube/sshutil" "os" ) @@ -42,14 +40,12 @@ var addCacheCmd = &cobra.Command{ Long: "Add an image to local cache.", Run: func(cmd *cobra.Command, args []string) { // Cache and load images into docker daemon - err := cacheAndLoadImages(args) - if err != nil { + if err := machine.CacheAndLoadImages(args); err != nil { fmt.Fprintf(os.Stderr, "Error caching and loading images: %s\n", err) os.Exit(1) } // Add images to config file - err = cmdConfig.AddToConfigArray("cache", args) - if err != nil { + if err := cmdConfig.AddToConfigMap(constants.Cache, args); err != nil { fmt.Fprintf(os.Stderr, "Error adding cached images to config file: %s\n", err) os.Exit(1) } @@ -62,25 +58,16 @@ var deleteCacheCmd = &cobra.Command{ Short: "Delete an image from the local cache.", Long: "Delete an image from the local cache.", Run: func(cmd *cobra.Command, args []string) { - - cmdRunner, err := getCommandRunner() - if err != nil { - fmt.Fprintf(os.Stderr, "Error getting command runner: %s\n", err) + // Delete images from config file + if err := cmdConfig.DeleteFromConfigMap(constants.Cache, args); err != nil { + fmt.Fprintf(os.Stderr, "Error deleting images from config file: %s\n", err) os.Exit(1) } - // Delete images from docker daemon - err = machine.DeleteImages(cmdRunner, args) - if err != nil { + // Delete images from cache/images directory + if err := machine.DeleteFromImageCacheDir(args); err != nil { fmt.Fprintf(os.Stderr, "Error deleting images: %s\n", err) os.Exit(1) } - // Delete images from config file - err = cmdConfig.DeleteFromConfigArray("cache", args) - if err != nil { - fmt.Fprintf(os.Stderr, "Error deleting images from config file: %s\n", err) - os.Exit(1) - } - }, } @@ -90,56 +77,14 @@ func LoadCachedImagesInConfigFile() error { if err != nil { return err } - - values := configFile["cache"] - - if values == nil { - return nil - } - - var images []string - - for _, v := range values.([]interface{}) { - images = append(images, v.(string)) - } - - return cacheAndLoadImages(images) - -} - -func cacheAndLoadImages(images []string) error { - - err := machine.CacheImages(images, constants.ImageCacheDir) - if err != nil { - return err - } - - cmdRunner, err := getCommandRunner() - if err != nil { - return err - } - - return machine.LoadImages(cmdRunner, images, constants.ImageCacheDir) - -} - -func getCommandRunner() (*bootstrapper.SSHRunner, error) { - api, err := machine.NewAPIClient() - if err != nil { - return nil, err - } - defer api.Close() - h, err := api.Load(config.GetMachineName()) - if err != nil { - return nil, err - } - - client, err := sshutil.NewSSHClient(h.Driver) - if err != nil { - return nil, err + if values, ok := configFile[constants.Cache]; ok { + var images []string + for key := range values.(map[string]interface{}) { + images = append(images, key) + } + return machine.CacheAndLoadImages(images) } - return bootstrapper.NewSSHRunner(client), nil - + return nil } func init() { diff --git a/cmd/minikube/cmd/config/config.go b/cmd/minikube/cmd/config/config.go index 73e08fb84415..15bad2c56294 100644 --- a/cmd/minikube/cmd/config/config.go +++ b/cmd/minikube/cmd/config/config.go @@ -36,7 +36,7 @@ type setFn func(string, string) error type Setting struct { name string set func(config.MinikubeConfig, string, string) error - setArray func(config.MinikubeConfig, string, []string) error + setMap func(config.MinikubeConfig, string, map[string]interface{}) error validations []setFn callbacks []setFn } @@ -195,8 +195,8 @@ var settings = []Setting{ set: SetBool, }, { - name: "cache", - setArray: SetStringArray, + name: "cache", + setMap: SetMap, }, } @@ -218,38 +218,35 @@ func configurableFields() string { return strings.Join(fields, "\n") } -// AddToConfigArray adds entries to an array in the config file -func AddToConfigArray(name string, images []string) error { +// AddToConfigMap adds entries to a map in the config file +func AddToConfigMap(name string, images []string) error { s, err := findSetting(name) if err != nil { return err } - // Set the values configFile, err := config.ReadConfig() if err != nil { return err } - values := configFile[name] - - // Add images to currently existing values in config file - if values != nil { - for _, v := range values.([]interface{}) { - images = append(images, v.(string)) + newImages := make(map[string]interface{}) + for _, image := range images { + newImages[image] = nil + } + if values, ok := configFile[name].(map[string]interface{}); ok { + for key := range values { + newImages[key] = nil } } - - err = s.setArray(configFile, name, images) - if err != nil { + if err = s.setMap(configFile, name, newImages); err != nil { return err } - // Write the values return WriteConfig(configFile) } -// DeleteFromConfigArray deletes entries in an array in the config file -func DeleteFromConfigArray(name string, images []string) error { +// DeleteFromConfigMap deletes entries from a map in the config file +func DeleteFromConfigMap(name string, images []string) error { s, err := findSetting(name) if err != nil { return err @@ -259,34 +256,16 @@ func DeleteFromConfigArray(name string, images []string) error { if err != nil { return err } - values := configFile[name] - if values == nil { + values, ok := configFile[name] + if !ok { return nil } - var finalImages []string - - if values != nil { - // Add images that are in config file but not in images to finalImages - // These are the images that should remain in the config file after deletion - for _, v := range values.([]interface{}) { - addImage := true - for _, image := range images { - if v.(string) == image { - addImage = false - } - } - if addImage { - finalImages = append(finalImages, v.(string)) - } - - } + for _, image := range images { + delete(values.(map[string]interface{}), image) } - - err = s.setArray(configFile, name, finalImages) - if err != nil { + if err = s.setMap(configFile, name, values.(map[string]interface{})); err != nil { return err } - // Write the values return WriteConfig(configFile) } diff --git a/cmd/minikube/cmd/config/util.go b/cmd/minikube/cmd/config/util.go index 9c2ea2f29371..5a2db1d7afbf 100644 --- a/cmd/minikube/cmd/config/util.go +++ b/cmd/minikube/cmd/config/util.go @@ -60,7 +60,7 @@ func SetString(m config.MinikubeConfig, name string, val string) error { return nil } -func SetStringArray(m config.MinikubeConfig, name string, val []string) error { +func SetMap(m config.MinikubeConfig, name string, val map[string]interface{}) error { m[name] = val return nil } diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 0404c3a44dbe..7739db35142d 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -338,7 +338,6 @@ This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_ if err != nil { fmt.Println("Unable to load cached images from config file.") } - } func validateK8sVersion(version string) { diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index 7d33e665eb3b..e091aa60290d 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -66,6 +66,9 @@ const DefaultMachineName = "minikube" // The name of the default storage class provisioner const DefaultStorageClassProvisioner = "standard" +// Used to modify the cache field in the config file +const Cache = "cache" + // MakeMiniPath is a utility to calculate a relative path to our directory. func MakeMiniPath(fileName ...string) string { args := []string{GetMinipath()} diff --git a/pkg/minikube/machine/cache_images.go b/pkg/minikube/machine/cache_images.go index 15f2e91422f2..ec26c0230e0c 100644 --- a/pkg/minikube/machine/cache_images.go +++ b/pkg/minikube/machine/cache_images.go @@ -27,7 +27,9 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" + "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/sshutil" "github.com/containers/image/copy" "github.com/containers/image/docker" @@ -97,25 +99,30 @@ func LoadImages(cmd bootstrapper.CommandRunner, images []string, cacheDir string return nil } -// DeleteImages deletes images from local daemon -func DeleteImages(cmd bootstrapper.CommandRunner, images []string) error { - var g errgroup.Group - for _, image := range images { - image := image - g.Go(func() error { - dockerDeleteCmd := "docker rmi " + image - if err := cmd.Run(dockerDeleteCmd); err != nil { - return errors.Wrapf(err, "deleting docker image: %s", image) - } - return nil - }) +func CacheAndLoadImages(images []string) error { + if err := CacheImages(images, constants.ImageCacheDir); err != nil { + return err } - if err := g.Wait(); err != nil { - return errors.Wrap(err, "deleting cached images") + api, err := NewAPIClient() + if err != nil { + return err + } + defer api.Close() + h, err := api.Load(config.GetMachineName()) + if err != nil { + return err + } + + client, err := sshutil.NewSSHClient(h.Driver) + if err != nil { + return err + } + cmdRunner, err := bootstrapper.NewSSHRunner(client), nil + if err != nil { + return err } - glog.Infoln("Successfully deleted cached images.") - return nil + return LoadImages(cmdRunner, images, constants.ImageCacheDir) } // # ParseReference cannot have a : in the directory path @@ -205,7 +212,7 @@ func LoadFromCacheBlocking(cmd bootstrapper.CommandRunner, src string) error { return errors.Wrapf(err, "loading docker image: %s", dst) } - if err := cmd.Run("sudo rm -rf " + dst); err != nil { + if err := cmd.Run("rm -rf " + dst); err != nil { return errors.Wrap(err, "deleting temp docker image location") } @@ -213,6 +220,43 @@ func LoadFromCacheBlocking(cmd bootstrapper.CommandRunner, src string) error { return nil } +func DeleteFromImageCacheDir(images []string) error { + for _, image := range images { + path := filepath.Join(constants.ImageCacheDir, image) + glog.Infoln("Deleting image in cache at ", path) + if err := os.Remove(path); err != nil { + return err + } + } + return cleanImageCacheDir() +} + +func cleanImageCacheDir() error { + err := filepath.Walk(constants.ImageCacheDir, func(path string, info os.FileInfo, err error) error { + // If error is not nil, it's because the path was already deleted and doesn't exist + // Move on to next path + if err != nil { + return nil + } + // Check if path is directory + if !info.IsDir() { + return nil + } + // If directory is empty, delete it + entries, err := ioutil.ReadDir(path) + if err != nil { + return err + } + if len(entries) == 0 { + if err = os.Remove(path); err != nil { + return err + } + } + return nil + }) + return err +} + func getSrcRef(image string) (types.ImageReference, error) { srcRef, err := docker.ParseReference("//" + image) if err != nil {