Fixing Volumes on Windows

pull/6/head
Jitendra Bhurat 2016-11-01 10:10:59 -04:00 committed by Paulo Pires
parent a659ac99b6
commit 66a1ef25e0
No known key found for this signature in database
GPG Key ID: F3F6ED5C522EAA71
6 changed files with 83 additions and 20 deletions

View File

@ -1463,8 +1463,6 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath
}
if len(mnt.MountPath) == 0 {
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) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))

View File

@ -28,6 +28,7 @@ import (
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
@ -57,7 +58,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/kubelet/util/cache"
"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/securitycontext"
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 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.
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)
} else {
glog.Errorf("Failed to encode pod: %s for prestop hook", pod.Name)
@ -677,6 +678,12 @@ func (dm *DockerManager) runContainer(
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
sysctls, unsafeSysctls, err := api.SysctlsFromPodAnnotations(pod.Annotations)
if err != nil {
@ -1586,7 +1593,7 @@ func containerAndPodFromLabels(inspect *dockertypes.ContainerJSON) (pod *api.Pod
// the pod data may not be set
if body, found := labels[kubernetesPodLabel]; found {
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]
for ix := range pod.Spec.Containers {
if pod.Spec.Containers[ix].Name == name {

View File

@ -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 already mounting on /etc/hosts
// 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)
mounts := []kubecontainer.Mount{}
for _, mount := range container.VolumeMounts {
@ -108,9 +109,21 @@ func makeMounts(pod *api.Pod, podDir string, container *api.Container, hostName,
if 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{
Name: mount.Name,
ContainerPath: mount.MountPath,
ContainerPath: containerPath,
HostPath: hostPath,
ReadOnly: mount.ReadOnly,
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)
if err != nil {
return nil, err
}
opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
if err != nil {
return nil, err
}
opts.Envs, err = kl.makeEnvironmentVariables(pod, container, podIP)
if err != nil {
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" {
p := kl.getPodContainerDir(pod.UID, container.Name)
if err := os.MkdirAll(p, 0750); err != nil {

View File

@ -18,6 +18,8 @@ package secret
import (
"fmt"
"path/filepath"
"runtime"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
@ -157,7 +159,12 @@ func (sv *secretVolume) GetAttributes() volume.Attributes {
}
}
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 {
@ -269,7 +276,12 @@ type secretVolumeUnmounter struct {
var _ volume.Unmounter = &secretVolumeUnmounter{}
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 {

View File

@ -23,6 +23,7 @@ import (
"os"
"path"
"path/filepath"
"runtime"
"strings"
"time"
@ -183,7 +184,14 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection) error {
}
// (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.RemoveAll(tsDir)
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(relativePath, "/")
if runtime.GOOS == "windows" {
relativePath = strings.TrimPrefix(relativePath, "\\")
} else {
relativePath = strings.TrimPrefix(relativePath, "/")
}
if strings.HasPrefix(relativePath, "..") {
return nil
}

View File

@ -20,10 +20,11 @@ import (
"io"
"io/ioutil"
"os"
"path"
filepath "path/filepath"
"runtime"
"time"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/types"
@ -211,7 +212,7 @@ func (err deletedVolumeInUseError) Error() string {
}
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 {
return "", err
}
@ -221,6 +222,7 @@ func RenameDirectory(oldPath, newName string) (string, error) {
if runtime.GOOS == "windows" {
err = copyFolder(oldPath, newPath)
if err != nil {
glog.Errorf("Error copying folder from: %s to: %s with error: %v", oldPath, newPath, err)
return "", err
}
os.RemoveAll(oldPath)
@ -235,12 +237,31 @@ func RenameDirectory(oldPath, newName string) (string, 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)
defer directory.Close()
objects, err := directory.Readdir(-1)
for _, obj := range objects {
sourcefilepointer := source + "/" + obj.Name()
destinationfilepointer := dest + "/" + obj.Name()
if obj.Mode()&os.ModeSymlink != 0 {
continue
}
sourcefilepointer := source + "\\" + obj.Name()
destinationfilepointer := dest + "\\" + obj.Name()
if obj.IsDir() {
err = copyFolder(sourcefilepointer, destinationfilepointer)
if err != nil {