提交 8e319bd0 编写于 作者: M Matt Rickard 提交者: GitHub

Merge pull request #2000 from hirsim/enable-cache-image-for-windows

Enable cache image for Windows
......@@ -19,6 +19,7 @@ package machine
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
......@@ -40,6 +41,8 @@ import (
const tempLoadDir = "/tmp"
var getWindowsVolumeName = getWindowsVolumeNameCmd
func CacheImagesForBootstrapper(version string, clusterBootstrapper string) error {
images := bootstrapper.GetCachedImageList(version, clusterBootstrapper)
......@@ -97,7 +100,7 @@ func LoadImages(cmd bootstrapper.CommandRunner, images []string, cacheDir string
// # ParseReference cannot have a : in the directory path
func sanitizeCacheDir(image string) string {
if hasWindowsDriveLetter(image) {
if runtime.GOOS == "windows" && hasWindowsDriveLetter(image) {
// not sanitize Windows drive letter.
return image[:2] + strings.Replace(image[2:], ":", "_", -1)
}
......@@ -105,9 +108,6 @@ func sanitizeCacheDir(image string) string {
}
func hasWindowsDriveLetter(s string) bool {
if runtime.GOOS != "windows" {
return false
}
if len(s) < 3 {
return false
}
......@@ -122,6 +122,46 @@ func hasWindowsDriveLetter(s string) bool {
return false
}
// Replace a drive letter to a volume name.
func replaceWinDriveLetterToVolumeName(s string) (string, error) {
vname, err := getWindowsVolumeName(s[:1])
if err != nil {
return "", err
}
path := vname + s[3:]
if _, err := os.Stat(filepath.Dir(path)); err != nil {
return "", err
}
return path, nil
}
func getWindowsVolumeNameCmd(d string) (string, error) {
cmd := exec.Command("wmic", "volume", "where", "DriveLetter = '"+d+":'", "get", "DeviceID")
stdout, err := cmd.Output()
if err != nil {
return "", err
}
outs := strings.Split(strings.Replace(string(stdout), "\r", "", -1), "\n")
var vname string
for _, l := range outs {
s := strings.TrimSpace(l)
if strings.HasPrefix(s, `\\?\Volume{`) && strings.HasSuffix(s, `}\`) {
vname = s
break
}
}
if vname == "" {
return "", errors.New("failed to get a volume GUID")
}
return vname, nil
}
func LoadFromCacheBlocking(cmd bootstrapper.CommandRunner, src string) error {
glog.Infoln("Loading image from cache at ", src)
filename := filepath.Base(src)
......@@ -162,6 +202,19 @@ func getSrcRef(image string) (types.ImageReference, error) {
}
func getDstRef(image, dst string) (types.ImageReference, error) {
if runtime.GOOS == "windows" && hasWindowsDriveLetter(dst) {
// ParseReference does not support a Windows drive letter.
// Therefore, will replace the drive letter to a volume name.
var err error
if dst, err = replaceWinDriveLetterToVolumeName(dst); err != nil {
return nil, errors.Wrap(err, "parsing docker archive dst ref: replace a Win drive letter to a volume name")
}
}
return _getDstRef(image, dst)
}
func _getDstRef(image, dst string) (types.ImageReference, error) {
dstRef, err := archive.ParseReference(dst + ":" + image)
if err != nil {
return nil, errors.Wrap(err, "parsing docker archive dst ref")
......@@ -179,13 +232,6 @@ func CacheImage(image, dst string) error {
return errors.Wrapf(err, "making cache image directory: %s", dst)
}
// TODO: support Windows drive letter.
// L:164 ParseReference does not support Windows drive letter.
// If contains Windows drive letter, it disable cache image for now.
if hasWindowsDriveLetter(dst) {
return nil
}
srcRef, err := getSrcRef(image)
if err != nil {
return errors.Wrap(err, "creating docker image src ref")
......
......@@ -17,6 +17,10 @@ limitations under the License.
package machine
import (
"io/ioutil"
"os"
"runtime"
"strings"
"testing"
"k8s.io/minikube/pkg/minikube/constants"
......@@ -29,3 +33,69 @@ func TestGetSrcRef(t *testing.T) {
}
}
}
func TestGetDstRef(t *testing.T) {
paths := []struct {
path, separator string
}{
{`/Users/foo/.minikube/cache/images`, `/`},
{`/home/foo/.minikube/cache/images`, `/`},
{`\\?\Volume{aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee}\Users\foo\.minikube\cache\images`, `\`},
{`\\?\Volume{aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee}\minikube\.minikube\cache\images`, `\`},
}
cases := []struct {
image, dst string
}{}
for _, tp := range paths {
for _, image := range constants.LocalkubeCachedImages {
dst := strings.Join([]string{tp.path, strings.Replace(image, ":", "_", -1)}, tp.separator)
cases = append(cases, struct{ image, dst string }{image, dst})
}
}
for _, tc := range cases {
if _, err := _getDstRef(tc.image, tc.dst); err != nil {
t.Errorf("Error getting dst ref for %s: %s", tc.dst, err)
}
}
}
func TestReplaceWinDriveLetterToVolumeName(t *testing.T) {
path, err := ioutil.TempDir("", "repwindl2vn")
if err != nil {
t.Fatalf("Error make tmp directory: %s", err)
}
defer os.RemoveAll(path)
if runtime.GOOS != "windows" {
// Replace to fake func.
getWindowsVolumeName = func(d string) (string, error) {
return `/`, nil
}
// Add dummy Windows drive letter.
path = `C:` + path
}
if _, err := replaceWinDriveLetterToVolumeName(path); err != nil {
t.Errorf("Error replace a Windows drive letter to a volume name: %s", err)
}
}
func TestHasWindowsDriveLetter(t *testing.T) {
cases := []struct {
path string
want bool
}{
{`C:\Users\Foo\.minikube`, true},
{`D:\minikube\.minikube`, true},
{`C\Foo\Bar\.minikube`, false},
{`/home/foo/.minikube`, false},
}
for _, tc := range cases {
if hasWindowsDriveLetter(tc.path) != tc.want {
t.Errorf("%s have a Windows drive letter: %t", tc.path, tc.want)
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册