Skip to content

Commit 43e4b0c

Browse files
authored
Merge pull request #2203 from priyawadhwa/cache-images
Add cache command to cache non-minikube images
2 parents a976d49 + 6344d0b commit 43e4b0c

File tree

6 files changed

+244
-3
lines changed

6 files changed

+244
-3
lines changed

Diff for: cmd/minikube/cmd/cache.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"github.com/spf13/cobra"
22+
cmdConfig "k8s.io/minikube/cmd/minikube/cmd/config"
23+
"k8s.io/minikube/pkg/minikube/config"
24+
"k8s.io/minikube/pkg/minikube/constants"
25+
"k8s.io/minikube/pkg/minikube/machine"
26+
"os"
27+
)
28+
29+
// cacheCmd represents the cache command
30+
var cacheCmd = &cobra.Command{
31+
Use: "cache",
32+
Short: "Add or delete an image from the local cache.",
33+
Long: "Add or delete an image from the local cache.",
34+
}
35+
36+
// addCacheCmd represents the cache add command
37+
var addCacheCmd = &cobra.Command{
38+
Use: "add",
39+
Short: "Add an image to local cache.",
40+
Long: "Add an image to local cache.",
41+
Run: func(cmd *cobra.Command, args []string) {
42+
// Cache and load images into docker daemon
43+
if err := machine.CacheAndLoadImages(args); err != nil {
44+
fmt.Fprintf(os.Stderr, "Error caching and loading images: %s\n", err)
45+
os.Exit(1)
46+
}
47+
// Add images to config file
48+
if err := cmdConfig.AddToConfigMap(constants.Cache, args); err != nil {
49+
fmt.Fprintf(os.Stderr, "Error adding cached images to config file: %s\n", err)
50+
os.Exit(1)
51+
}
52+
},
53+
}
54+
55+
// deleteCacheCmd represents the cache delete command
56+
var deleteCacheCmd = &cobra.Command{
57+
Use: "delete",
58+
Short: "Delete an image from the local cache.",
59+
Long: "Delete an image from the local cache.",
60+
Run: func(cmd *cobra.Command, args []string) {
61+
// Delete images from config file
62+
if err := cmdConfig.DeleteFromConfigMap(constants.Cache, args); err != nil {
63+
fmt.Fprintf(os.Stderr, "Error deleting images from config file: %s\n", err)
64+
os.Exit(1)
65+
}
66+
// Delete images from cache/images directory
67+
if err := machine.DeleteFromImageCacheDir(args); err != nil {
68+
fmt.Fprintf(os.Stderr, "Error deleting images: %s\n", err)
69+
os.Exit(1)
70+
}
71+
},
72+
}
73+
74+
// LoadCachedImagesInConfigFile loads the images currently in the config file (minikube start)
75+
func LoadCachedImagesInConfigFile() error {
76+
configFile, err := config.ReadConfig()
77+
if err != nil {
78+
return err
79+
}
80+
if values, ok := configFile[constants.Cache]; ok {
81+
var images []string
82+
for key := range values.(map[string]interface{}) {
83+
images = append(images, key)
84+
}
85+
return machine.CacheAndLoadImages(images)
86+
}
87+
return nil
88+
}
89+
90+
func init() {
91+
cacheCmd.AddCommand(addCacheCmd)
92+
cacheCmd.AddCommand(deleteCacheCmd)
93+
RootCmd.AddCommand(cacheCmd)
94+
}

Diff for: cmd/minikube/cmd/config/config.go

+58
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type setFn func(string, string) error
3636
type Setting struct {
3737
name string
3838
set func(config.MinikubeConfig, string, string) error
39+
setMap func(config.MinikubeConfig, string, map[string]interface{}) error
3940
validations []setFn
4041
callbacks []setFn
4142
}
@@ -193,6 +194,11 @@ var settings = []Setting{
193194
name: "disable-driver-mounts",
194195
set: SetBool,
195196
},
197+
{
198+
name: "cache",
199+
set: SetConfigMap,
200+
setMap: SetMap,
201+
},
196202
}
197203

198204
var ConfigCmd = &cobra.Command{
@@ -213,6 +219,58 @@ func configurableFields() string {
213219
return strings.Join(fields, "\n")
214220
}
215221

222+
// AddToConfigMap adds entries to a map in the config file
223+
func AddToConfigMap(name string, images []string) error {
224+
s, err := findSetting(name)
225+
if err != nil {
226+
return err
227+
}
228+
// Set the values
229+
configFile, err := config.ReadConfig()
230+
if err != nil {
231+
return err
232+
}
233+
newImages := make(map[string]interface{})
234+
for _, image := range images {
235+
newImages[image] = nil
236+
}
237+
if values, ok := configFile[name].(map[string]interface{}); ok {
238+
for key := range values {
239+
newImages[key] = nil
240+
}
241+
}
242+
if err = s.setMap(configFile, name, newImages); err != nil {
243+
return err
244+
}
245+
// Write the values
246+
return WriteConfig(configFile)
247+
}
248+
249+
// DeleteFromConfigMap deletes entries from a map in the config file
250+
func DeleteFromConfigMap(name string, images []string) error {
251+
s, err := findSetting(name)
252+
if err != nil {
253+
return err
254+
}
255+
// Set the values
256+
configFile, err := config.ReadConfig()
257+
if err != nil {
258+
return err
259+
}
260+
values, ok := configFile[name]
261+
if !ok {
262+
return nil
263+
}
264+
for _, image := range images {
265+
delete(values.(map[string]interface{}), image)
266+
}
267+
if err = s.setMap(configFile, name, values.(map[string]interface{})); err != nil {
268+
return err
269+
}
270+
// Write the values
271+
return WriteConfig(configFile)
272+
}
273+
216274
// WriteConfig writes a minikube config to the JSON file
217275
func WriteConfig(m config.MinikubeConfig) error {
218276
f, err := os.Create(constants.ConfigFile)

Diff for: cmd/minikube/cmd/config/util.go

+16
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"os"
2222
"strconv"
23+
"strings"
2324

2425
"github.com/pkg/errors"
2526
"k8s.io/minikube/pkg/minikube/assets"
@@ -60,6 +61,21 @@ func SetString(m config.MinikubeConfig, name string, val string) error {
6061
return nil
6162
}
6263

64+
func SetMap(m config.MinikubeConfig, name string, val map[string]interface{}) error {
65+
m[name] = val
66+
return nil
67+
}
68+
69+
func SetConfigMap(m config.MinikubeConfig, name string, val string) error {
70+
list := strings.Split(val, ",")
71+
v := make(map[string]interface{})
72+
for _, s := range list {
73+
v[s] = nil
74+
}
75+
m[name] = v
76+
return nil
77+
}
78+
6379
func SetInt(m config.MinikubeConfig, name string, val string) error {
6480
i, err := strconv.Atoi(val)
6581
if err != nil {

Diff for: cmd/minikube/cmd/start.go

+6
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,12 @@ This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_
332332
cmdutil.MaybeReportErrorAndExit(err)
333333
}
334334
}
335+
336+
fmt.Println("Loading cached images from config file.")
337+
err = LoadCachedImagesInConfigFile()
338+
if err != nil {
339+
fmt.Println("Unable to load cached images from config file.")
340+
}
335341
}
336342

337343
func validateK8sVersion(version string) {

Diff for: pkg/minikube/constants/constants.go

+3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ const DefaultMachineName = "minikube"
6666
// The name of the default storage class provisioner
6767
const DefaultStorageClassProvisioner = "standard"
6868

69+
// Used to modify the cache field in the config file
70+
const Cache = "cache"
71+
6972
// MakeMiniPath is a utility to calculate a relative path to our directory.
7073
func MakeMiniPath(fileName ...string) string {
7174
args := []string{GetMinipath()}

Diff for: pkg/minikube/machine/cache_images.go

+67-3
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ limitations under the License.
1717
package machine
1818

1919
import (
20+
"golang.org/x/sync/errgroup"
2021
"io/ioutil"
2122
"os"
2223
"os/exec"
2324
"path/filepath"
2425
"runtime"
2526
"strings"
2627

27-
"golang.org/x/sync/errgroup"
28-
2928
"k8s.io/minikube/pkg/minikube/assets"
3029
"k8s.io/minikube/pkg/minikube/bootstrapper"
30+
"k8s.io/minikube/pkg/minikube/config"
3131
"k8s.io/minikube/pkg/minikube/constants"
32+
"k8s.io/minikube/pkg/minikube/sshutil"
3233

3334
"github.com/containers/image/copy"
3435
"github.com/containers/image/docker"
@@ -98,6 +99,32 @@ func LoadImages(cmd bootstrapper.CommandRunner, images []string, cacheDir string
9899
return nil
99100
}
100101

102+
func CacheAndLoadImages(images []string) error {
103+
if err := CacheImages(images, constants.ImageCacheDir); err != nil {
104+
return err
105+
}
106+
api, err := NewAPIClient()
107+
if err != nil {
108+
return err
109+
}
110+
defer api.Close()
111+
h, err := api.Load(config.GetMachineName())
112+
if err != nil {
113+
return err
114+
}
115+
116+
client, err := sshutil.NewSSHClient(h.Driver)
117+
if err != nil {
118+
return err
119+
}
120+
cmdRunner, err := bootstrapper.NewSSHRunner(client), nil
121+
if err != nil {
122+
return err
123+
}
124+
125+
return LoadImages(cmdRunner, images, constants.ImageCacheDir)
126+
}
127+
101128
// # ParseReference cannot have a : in the directory path
102129
func sanitizeCacheDir(image string) string {
103130
if runtime.GOOS == "windows" && hasWindowsDriveLetter(image) {
@@ -185,14 +212,51 @@ func LoadFromCacheBlocking(cmd bootstrapper.CommandRunner, src string) error {
185212
return errors.Wrapf(err, "loading docker image: %s", dst)
186213
}
187214

188-
if err := cmd.Run("rm -rf " + dst); err != nil {
215+
if err := cmd.Run("sudo rm -rf " + dst); err != nil {
189216
return errors.Wrap(err, "deleting temp docker image location")
190217
}
191218

192219
glog.Infof("Successfully loaded image %s from cache", src)
193220
return nil
194221
}
195222

223+
func DeleteFromImageCacheDir(images []string) error {
224+
for _, image := range images {
225+
path := filepath.Join(constants.ImageCacheDir, image)
226+
glog.Infoln("Deleting image in cache at ", path)
227+
if err := os.Remove(path); err != nil {
228+
return err
229+
}
230+
}
231+
return cleanImageCacheDir()
232+
}
233+
234+
func cleanImageCacheDir() error {
235+
err := filepath.Walk(constants.ImageCacheDir, func(path string, info os.FileInfo, err error) error {
236+
// If error is not nil, it's because the path was already deleted and doesn't exist
237+
// Move on to next path
238+
if err != nil {
239+
return nil
240+
}
241+
// Check if path is directory
242+
if !info.IsDir() {
243+
return nil
244+
}
245+
// If directory is empty, delete it
246+
entries, err := ioutil.ReadDir(path)
247+
if err != nil {
248+
return err
249+
}
250+
if len(entries) == 0 {
251+
if err = os.Remove(path); err != nil {
252+
return err
253+
}
254+
}
255+
return nil
256+
})
257+
return err
258+
}
259+
196260
func getSrcRef(image string) (types.ImageReference, error) {
197261
srcRef, err := docker.ParseReference("//" + image)
198262
if err != nil {

0 commit comments

Comments
 (0)