Merge pull request #6034 from claudiubelu/windows/fixes-image-volume
Fixes Windows containers with image volumes
This commit is contained in:
commit
7b8a697f28
@ -18,6 +18,7 @@ package mount
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -50,15 +51,21 @@ func (m *Mount) Mount(target string) error {
|
|||||||
if err = hcsshim.ActivateLayer(di, layerID); err != nil {
|
if err = hcsshim.ActivateLayer(di, layerID); err != nil {
|
||||||
return errors.Wrapf(err, "failed to activate layer %s", m.Source)
|
return errors.Wrapf(err, "failed to activate layer %s", m.Source)
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
hcsshim.DeactivateLayer(di, layerID)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = hcsshim.PrepareLayer(di, layerID, parentLayerPaths); err != nil {
|
if err = hcsshim.PrepareLayer(di, layerID, parentLayerPaths); err != nil {
|
||||||
return errors.Wrapf(err, "failed to prepare layer %s", m.Source)
|
return errors.Wrapf(err, "failed to prepare layer %s", m.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can link the layer mount path to the given target. It is an UNC path, and it needs
|
||||||
|
// a trailing backslash.
|
||||||
|
mountPath, err := hcsshim.GetLayerMountPath(di, layerID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to get layer mount path for %s", m.Source)
|
||||||
|
}
|
||||||
|
mountPath = mountPath + `\`
|
||||||
|
if err = os.Symlink(mountPath, target); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to link mount to taget %s", target)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
goruntime "runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
@ -75,20 +77,41 @@ func WithVolumes(volumeMounts map[string]string) containerd.NewContainerOpts {
|
|||||||
// refer to https://github.com/containerd/containerd/pull/1868
|
// refer to https://github.com/containerd/containerd/pull/1868
|
||||||
// https://github.com/containerd/containerd/pull/1785
|
// https://github.com/containerd/containerd/pull/1785
|
||||||
defer os.Remove(root) // nolint: errcheck
|
defer os.Remove(root) // nolint: errcheck
|
||||||
if err := mount.All(mounts, root); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to mount")
|
unmounter := func(mountPath string) {
|
||||||
}
|
if uerr := mount.Unmount(mountPath, 0); uerr != nil {
|
||||||
defer func() {
|
log.G(ctx).WithError(uerr).Errorf("Failed to unmount snapshot %q", root)
|
||||||
if uerr := mount.Unmount(root, 0); uerr != nil {
|
|
||||||
log.G(ctx).WithError(uerr).Errorf("Failed to unmount snapshot %q", c.SnapshotKey)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = uerr
|
err = uerr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
|
||||||
|
var mountPaths []string
|
||||||
|
if goruntime.GOOS == "windows" {
|
||||||
|
for _, m := range mounts {
|
||||||
|
// appending the layerID to the root.
|
||||||
|
mountPath := filepath.Join(root, filepath.Base(m.Source))
|
||||||
|
mountPaths = append(mountPaths, mountPath)
|
||||||
|
if err := m.Mount(mountPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer unmounter(m.Source)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mountPaths = append(mountPaths, root)
|
||||||
|
if err := mount.All(mounts, root); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to mount")
|
||||||
|
}
|
||||||
|
defer unmounter(root)
|
||||||
|
}
|
||||||
|
|
||||||
for host, volume := range volumeMounts {
|
for host, volume := range volumeMounts {
|
||||||
src := filepath.Join(root, volume)
|
// The volume may have been defined with a C: prefix, which we can't use here.
|
||||||
|
volume = strings.TrimPrefix(volume, "C:")
|
||||||
|
for _, mountPath := range mountPaths {
|
||||||
|
src := filepath.Join(mountPath, volume)
|
||||||
if _, err := os.Stat(src); err != nil {
|
if _, err := os.Stat(src); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// Skip copying directory if it does not exist.
|
// Skip copying directory if it does not exist.
|
||||||
@ -100,6 +123,7 @@ func WithVolumes(volumeMounts map[string]string) containerd.NewContainerOpts {
|
|||||||
return errors.Wrap(err, "taking runtime copy of volume")
|
return errors.Wrap(err, "taking runtime copy of volume")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package opts
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -119,19 +120,28 @@ func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extr
|
|||||||
// paths, so don't use it.
|
// paths, so don't use it.
|
||||||
if !namedPipePath(src) {
|
if !namedPipePath(src) {
|
||||||
if _, err := osi.Stat(src); err != nil {
|
if _, err := osi.Stat(src); err != nil {
|
||||||
// If the source doesn't exist, return an error instead
|
// Create the host path if it doesn't exist. This will align
|
||||||
// of creating the source. This aligns with Docker's
|
// the behavior with the Linux implementation, but it doesn't
|
||||||
// behavior on windows.
|
// align with Docker's behavior on Windows.
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
return errors.Wrapf(err, "failed to stat %q", src)
|
return errors.Wrapf(err, "failed to stat %q", src)
|
||||||
}
|
}
|
||||||
|
if err := osi.MkdirAll(src, 0755); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to mkdir %q", src)
|
||||||
|
}
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
src, err = osi.ResolveSymbolicLink(src)
|
src, err = osi.ResolveSymbolicLink(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to resolve symlink %q", src)
|
return errors.Wrapf(err, "failed to resolve symlink %q", src)
|
||||||
}
|
}
|
||||||
// hcsshim requires clean path, especially '/' -> '\'.
|
// hcsshim requires clean path, especially '/' -> '\'. Additionally,
|
||||||
|
// for the destination, absolute paths should have the C: prefix.
|
||||||
src = filepath.Clean(src)
|
src = filepath.Clean(src)
|
||||||
dst = filepath.Clean(dst)
|
dst = filepath.Clean(dst)
|
||||||
|
if dst[0] == '\\' {
|
||||||
|
dst = "C:" + dst
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var options []string
|
var options []string
|
||||||
|
Loading…
Reference in New Issue
Block a user