mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Fixing Volumes on Windows
This commit is contained in:
		
				
					committed by
					
						
						Paulo Pires
					
				
			
			
				
	
			
			
			
						parent
						
							a659ac99b6
						
					
				
				
					commit
					66a1ef25e0
				
			@@ -1463,8 +1463,6 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		if len(mnt.MountPath) == 0 {
 | 
							if len(mnt.MountPath) == 0 {
 | 
				
			||||||
			allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"), ""))
 | 
								allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"), ""))
 | 
				
			||||||
		} else if strings.Contains(mnt.MountPath, ":") {
 | 
					 | 
				
			||||||
			allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must not contain ':'"))
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if mountpoints.Has(mnt.MountPath) {
 | 
							if mountpoints.Has(mnt.MountPath) {
 | 
				
			||||||
			allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))
 | 
								allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ import (
 | 
				
			|||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -57,7 +58,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/kubelet/types"
 | 
						"k8s.io/kubernetes/pkg/kubelet/types"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/util/cache"
 | 
						"k8s.io/kubernetes/pkg/kubelet/util/cache"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/util/format"
 | 
						"k8s.io/kubernetes/pkg/kubelet/util/format"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						kruntime "k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/security/apparmor"
 | 
						"k8s.io/kubernetes/pkg/security/apparmor"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/securitycontext"
 | 
						"k8s.io/kubernetes/pkg/securitycontext"
 | 
				
			||||||
	kubetypes "k8s.io/kubernetes/pkg/types"
 | 
						kubetypes "k8s.io/kubernetes/pkg/types"
 | 
				
			||||||
@@ -606,7 +607,7 @@ func (dm *DockerManager) runContainer(
 | 
				
			|||||||
		// TODO: This is kind of hacky, we should really just encode the bits we need.
 | 
							// TODO: This is kind of hacky, we should really just encode the bits we need.
 | 
				
			||||||
		// TODO: This is hacky because the Kubelet should be parameterized to encode a specific version
 | 
							// TODO: This is hacky because the Kubelet should be parameterized to encode a specific version
 | 
				
			||||||
		//   and needs to be able to migrate this whenever we deprecate v1. Should be a member of DockerManager.
 | 
							//   and needs to be able to migrate this whenever we deprecate v1. Should be a member of DockerManager.
 | 
				
			||||||
		if data, err := runtime.Encode(api.Codecs.LegacyCodec(unversioned.GroupVersion{Group: api.GroupName, Version: "v1"}), pod); err == nil {
 | 
							if data, err := kruntime.Encode(api.Codecs.LegacyCodec(unversioned.GroupVersion{Group: api.GroupName, Version: "v1"}), pod); err == nil {
 | 
				
			||||||
			labels[kubernetesPodLabel] = string(data)
 | 
								labels[kubernetesPodLabel] = string(data)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			glog.Errorf("Failed to encode pod: %s for prestop hook", pod.Name)
 | 
								glog.Errorf("Failed to encode pod: %s for prestop hook", pod.Name)
 | 
				
			||||||
@@ -677,6 +678,12 @@ func (dm *DockerManager) runContainer(
 | 
				
			|||||||
		SecurityOpt: fmtSecurityOpts,
 | 
							SecurityOpt: fmtSecurityOpts,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// There is no /etc/resolv.conf in Windows, DNS and DNSSearch options would have to be passed to Docker runtime instead
 | 
				
			||||||
 | 
						if runtime.GOOS == "windows" {
 | 
				
			||||||
 | 
							hc.DNS = opts.DNS
 | 
				
			||||||
 | 
							hc.DNSSearch = opts.DNSSearch
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set sysctls if requested
 | 
						// Set sysctls if requested
 | 
				
			||||||
	sysctls, unsafeSysctls, err := api.SysctlsFromPodAnnotations(pod.Annotations)
 | 
						sysctls, unsafeSysctls, err := api.SysctlsFromPodAnnotations(pod.Annotations)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -1586,7 +1593,7 @@ func containerAndPodFromLabels(inspect *dockertypes.ContainerJSON) (pod *api.Pod
 | 
				
			|||||||
	// the pod data may not be set
 | 
						// the pod data may not be set
 | 
				
			||||||
	if body, found := labels[kubernetesPodLabel]; found {
 | 
						if body, found := labels[kubernetesPodLabel]; found {
 | 
				
			||||||
		pod = &api.Pod{}
 | 
							pod = &api.Pod{}
 | 
				
			||||||
		if err = runtime.DecodeInto(api.Codecs.UniversalDecoder(), []byte(body), pod); err == nil {
 | 
							if err = kruntime.DecodeInto(api.Codecs.UniversalDecoder(), []byte(body), pod); err == nil {
 | 
				
			||||||
			name := labels[types.KubernetesContainerNameLabel]
 | 
								name := labels[types.KubernetesContainerNameLabel]
 | 
				
			||||||
			for ix := range pod.Spec.Containers {
 | 
								for ix := range pod.Spec.Containers {
 | 
				
			||||||
				if pod.Spec.Containers[ix].Name == name {
 | 
									if pod.Spec.Containers[ix].Name == name {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,7 +82,8 @@ func makeMounts(pod *api.Pod, podDir string, container *api.Container, hostName,
 | 
				
			|||||||
	// - container is not an infrastructure(pause) container
 | 
						// - container is not an infrastructure(pause) container
 | 
				
			||||||
	// - container is not already mounting on /etc/hosts
 | 
						// - container is not already mounting on /etc/hosts
 | 
				
			||||||
	// When the pause container is being created, its IP is still unknown. Hence, PodIP will not have been set.
 | 
						// When the pause container is being created, its IP is still unknown. Hence, PodIP will not have been set.
 | 
				
			||||||
	mountEtcHostsFile := (pod.Spec.SecurityContext == nil || !pod.Spec.SecurityContext.HostNetwork) && len(podIP) > 0
 | 
						// OS is not Windows
 | 
				
			||||||
 | 
						mountEtcHostsFile := (pod.Spec.SecurityContext == nil || !pod.Spec.SecurityContext.HostNetwork) && len(podIP) > 0 && runtime.GOOS != "windows"
 | 
				
			||||||
	glog.V(3).Infof("container: %v/%v/%v podIP: %q creating hosts mount: %v", pod.Namespace, pod.Name, container.Name, podIP, mountEtcHostsFile)
 | 
						glog.V(3).Infof("container: %v/%v/%v podIP: %q creating hosts mount: %v", pod.Namespace, pod.Name, container.Name, podIP, mountEtcHostsFile)
 | 
				
			||||||
	mounts := []kubecontainer.Mount{}
 | 
						mounts := []kubecontainer.Mount{}
 | 
				
			||||||
	for _, mount := range container.VolumeMounts {
 | 
						for _, mount := range container.VolumeMounts {
 | 
				
			||||||
@@ -108,9 +109,21 @@ func makeMounts(pod *api.Pod, podDir string, container *api.Container, hostName,
 | 
				
			|||||||
		if mount.SubPath != "" {
 | 
							if mount.SubPath != "" {
 | 
				
			||||||
			hostPath = filepath.Join(hostPath, mount.SubPath)
 | 
								hostPath = filepath.Join(hostPath, mount.SubPath)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Docker Volume Mounts fail on Windows if it is not of the form C:/
 | 
				
			||||||
 | 
							containerPath := mount.MountPath
 | 
				
			||||||
 | 
							if runtime.GOOS == "windows" {
 | 
				
			||||||
 | 
								if strings.HasPrefix(hostPath, "/") && !strings.Contains(hostPath, ":") {
 | 
				
			||||||
 | 
									hostPath = "c:" + hostPath
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if strings.HasPrefix(containerPath, "/") && !strings.Contains(containerPath, ":") {
 | 
				
			||||||
 | 
									containerPath = "c:" + containerPath
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mounts = append(mounts, kubecontainer.Mount{
 | 
							mounts = append(mounts, kubecontainer.Mount{
 | 
				
			||||||
			Name:           mount.Name,
 | 
								Name:           mount.Name,
 | 
				
			||||||
			ContainerPath:  mount.MountPath,
 | 
								ContainerPath:  containerPath,
 | 
				
			||||||
			HostPath:       hostPath,
 | 
								HostPath:       hostPath,
 | 
				
			||||||
			ReadOnly:       mount.ReadOnly,
 | 
								ReadOnly:       mount.ReadOnly,
 | 
				
			||||||
			SELinuxRelabel: relabelVolume,
 | 
								SELinuxRelabel: relabelVolume,
 | 
				
			||||||
@@ -262,17 +275,17 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *api.Pod, container *api.Cont
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if runtime.GOOS != "windows" {
 | 
						opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
 | 
				
			||||||
		opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
 | 
						if err != nil {
 | 
				
			||||||
		if err != nil {
 | 
							return nil, err
 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	opts.Envs, err = kl.makeEnvironmentVariables(pod, container, podIP)
 | 
						opts.Envs, err = kl.makeEnvironmentVariables(pod, container, podIP)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Disabling adding TerminationMessagePath on Windows as these files would be mounted as docker volume and
 | 
				
			||||||
 | 
						// Docker for Windows has a bug where only directories can be mounted
 | 
				
			||||||
	if len(container.TerminationMessagePath) != 0 && runtime.GOOS != "windows" {
 | 
						if len(container.TerminationMessagePath) != 0 && runtime.GOOS != "windows" {
 | 
				
			||||||
		p := kl.getPodContainerDir(pod.UID, container.Name)
 | 
							p := kl.getPodContainerDir(pod.UID, container.Name)
 | 
				
			||||||
		if err := os.MkdirAll(p, 0750); err != nil {
 | 
							if err := os.MkdirAll(p, 0750); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ package secret
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
@@ -157,7 +159,12 @@ func (sv *secretVolume) GetAttributes() volume.Attributes {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (b *secretVolumeMounter) SetUp(fsGroup *int64) error {
 | 
					func (b *secretVolumeMounter) SetUp(fsGroup *int64) error {
 | 
				
			||||||
	return b.SetUpAt(b.GetPath(), fsGroup)
 | 
						// Update each Slash "/" character for Windows with seperator character
 | 
				
			||||||
 | 
						dir := b.GetPath()
 | 
				
			||||||
 | 
						if runtime.GOOS == "windows" {
 | 
				
			||||||
 | 
							dir = filepath.FromSlash(dir)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return b.SetUpAt(dir, fsGroup)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *secretVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
 | 
					func (b *secretVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
 | 
				
			||||||
@@ -269,7 +276,12 @@ type secretVolumeUnmounter struct {
 | 
				
			|||||||
var _ volume.Unmounter = &secretVolumeUnmounter{}
 | 
					var _ volume.Unmounter = &secretVolumeUnmounter{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *secretVolumeUnmounter) TearDown() error {
 | 
					func (c *secretVolumeUnmounter) TearDown() error {
 | 
				
			||||||
	return c.TearDownAt(c.GetPath())
 | 
						// Update each Slash "/" character for Windows with seperator character
 | 
				
			||||||
 | 
						dir := c.GetPath()
 | 
				
			||||||
 | 
						if runtime.GOOS == "windows" {
 | 
				
			||||||
 | 
							dir = filepath.FromSlash(dir)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return c.TearDownAt(dir)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *secretVolumeUnmounter) TearDownAt(dir string) error {
 | 
					func (c *secretVolumeUnmounter) TearDownAt(dir string) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -183,7 +184,14 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// (9)
 | 
						// (9)
 | 
				
			||||||
	if err = os.Rename(newDataDirPath, dataDirPath); err != nil {
 | 
						if runtime.GOOS == "windows" {
 | 
				
			||||||
 | 
							os.Remove(dataDirPath)
 | 
				
			||||||
 | 
							err = os.Symlink(tsDirName, dataDirPath)
 | 
				
			||||||
 | 
							os.Remove(newDataDirPath)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err = os.Rename(newDataDirPath, dataDirPath)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		os.Remove(newDataDirPath)
 | 
							os.Remove(newDataDirPath)
 | 
				
			||||||
		os.RemoveAll(tsDir)
 | 
							os.RemoveAll(tsDir)
 | 
				
			||||||
		glog.Errorf("%s: error renaming symbolic link for data directory %s: %v", w.logContext, newDataDirPath, err)
 | 
							glog.Errorf("%s: error renaming symbolic link for data directory %s: %v", w.logContext, newDataDirPath, err)
 | 
				
			||||||
@@ -303,7 +311,11 @@ func (w *AtomicWriter) pathsToRemove(payload map[string]FileProjection) (sets.St
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		relativePath := strings.TrimPrefix(path, w.targetDir)
 | 
							relativePath := strings.TrimPrefix(path, w.targetDir)
 | 
				
			||||||
		relativePath = strings.TrimPrefix(relativePath, "/")
 | 
							if runtime.GOOS == "windows" {
 | 
				
			||||||
 | 
								relativePath = strings.TrimPrefix(relativePath, "\\")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								relativePath = strings.TrimPrefix(relativePath, "/")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if strings.HasPrefix(relativePath, "..") {
 | 
							if strings.HasPrefix(relativePath, "..") {
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,10 +20,11 @@ import (
 | 
				
			|||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						filepath "path/filepath"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/golang/glog"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/resource"
 | 
						"k8s.io/kubernetes/pkg/api/resource"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/types"
 | 
						"k8s.io/kubernetes/pkg/types"
 | 
				
			||||||
@@ -211,7 +212,7 @@ func (err deletedVolumeInUseError) Error() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func RenameDirectory(oldPath, newName string) (string, error) {
 | 
					func RenameDirectory(oldPath, newName string) (string, error) {
 | 
				
			||||||
	newPath, err := ioutil.TempDir(path.Dir(oldPath), newName)
 | 
						newPath, err := ioutil.TempDir(filepath.Dir(oldPath), newName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -221,6 +222,7 @@ func RenameDirectory(oldPath, newName string) (string, error) {
 | 
				
			|||||||
	if runtime.GOOS == "windows" {
 | 
						if runtime.GOOS == "windows" {
 | 
				
			||||||
		err = copyFolder(oldPath, newPath)
 | 
							err = copyFolder(oldPath, newPath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 | 
								glog.Errorf("Error copying folder from: %s to: %s with error: %v", oldPath, newPath, err)
 | 
				
			||||||
			return "", err
 | 
								return "", err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		os.RemoveAll(oldPath)
 | 
							os.RemoveAll(oldPath)
 | 
				
			||||||
@@ -235,12 +237,31 @@ func RenameDirectory(oldPath, newName string) (string, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func copyFolder(source string, dest string) (err error) {
 | 
					func copyFolder(source string, dest string) (err error) {
 | 
				
			||||||
 | 
						fi, err := os.Lstat(source)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("Error getting stats for %s. %v", source, err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = os.MkdirAll(dest, fi.Mode())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("Unable to create %s directory %v", dest, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	directory, _ := os.Open(source)
 | 
						directory, _ := os.Open(source)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer directory.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	objects, err := directory.Readdir(-1)
 | 
						objects, err := directory.Readdir(-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, obj := range objects {
 | 
						for _, obj := range objects {
 | 
				
			||||||
		sourcefilepointer := source + "/" + obj.Name()
 | 
							if obj.Mode()&os.ModeSymlink != 0 {
 | 
				
			||||||
		destinationfilepointer := dest + "/" + obj.Name()
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sourcefilepointer := source + "\\" + obj.Name()
 | 
				
			||||||
 | 
							destinationfilepointer := dest + "\\" + obj.Name()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if obj.IsDir() {
 | 
							if obj.IsDir() {
 | 
				
			||||||
			err = copyFolder(sourcefilepointer, destinationfilepointer)
 | 
								err = copyFolder(sourcefilepointer, destinationfilepointer)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user