diff --git a/pkg/os/os.go b/pkg/os/os.go index 6c562d42776c..ad5be5c0b850 100644 --- a/pkg/os/os.go +++ b/pkg/os/os.go @@ -20,6 +20,7 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "github.com/containerd/fifo" "github.com/docker/docker/pkg/mount" @@ -34,6 +35,7 @@ type OS interface { RemoveAll(path string) error OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) Stat(name string) (os.FileInfo, error) + ResolveSymbolicLink(name string) (string, error) CopyFile(src, dest string, perm os.FileMode) error WriteFile(filename string, data []byte, perm os.FileMode) error Mount(source string, target string, fstype string, flags uintptr, data string) error @@ -63,6 +65,18 @@ func (RealOS) Stat(name string) (os.FileInfo, error) { return os.Stat(name) } +// ResolveSymbolicLink will follow any symbolic links +func (RealOS) ResolveSymbolicLink(path string) (string, error) { + info, err := os.Lstat(path) + if err != nil { + return "", err + } + if info.Mode()&os.ModeSymlink != os.ModeSymlink { + return path, nil + } + return filepath.EvalSymlinks(path) +} + // CopyFile copys src file to dest file func (RealOS) CopyFile(src, dest string, perm os.FileMode) error { in, err := os.Open(src) diff --git a/pkg/os/testing/fake_os.go b/pkg/os/testing/fake_os.go index c1d5aa9b95d0..9ac5029b5492 100644 --- a/pkg/os/testing/fake_os.go +++ b/pkg/os/testing/fake_os.go @@ -39,16 +39,17 @@ type CalledDetail struct { // of the real call. type FakeOS struct { sync.Mutex - MkdirAllFn func(string, os.FileMode) error - RemoveAllFn func(string) error - OpenFifoFn func(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, error) - StatFn func(string) (os.FileInfo, error) - CopyFileFn func(string, string, os.FileMode) error - WriteFileFn func(string, []byte, os.FileMode) error - MountFn func(source string, target string, fstype string, flags uintptr, data string) error - UnmountFn func(target string, flags int) error - calls []CalledDetail - errors map[string]error + MkdirAllFn func(string, os.FileMode) error + RemoveAllFn func(string) error + OpenFifoFn func(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, error) + StatFn func(string) (os.FileInfo, error) + ResolveSymbolicLinkFn func(string) (string, error) + CopyFileFn func(string, string, os.FileMode) error + WriteFileFn func(string, []byte, os.FileMode) error + MountFn func(source string, target string, fstype string, flags uintptr, data string) error + UnmountFn func(target string, flags int) error + calls []CalledDetail + errors map[string]error } var _ osInterface.OS = &FakeOS{} @@ -160,6 +161,19 @@ func (f *FakeOS) Stat(name string) (os.FileInfo, error) { return nil, nil } +// ResolveSymbolicLink is a fake call that invokes ResolveSymbolicLinkFn or returns its input +func (f *FakeOS) ResolveSymbolicLink(path string) (string, error) { + f.appendCalls("ResolveSymbolicLink", path) + if err := f.getError("ResolveSymbolicLink"); err != nil { + return "", err + } + + if f.ResolveSymbolicLinkFn != nil { + return f.ResolveSymbolicLinkFn(path) + } + return path, nil +} + // CopyFile is a fake call that invokes CopyFileFn or just return nil. func (f *FakeOS) CopyFile(src, dest string, perm os.FileMode) error { f.appendCalls("CopyFile", src, dest, perm) diff --git a/pkg/server/container_create.go b/pkg/server/container_create.go index 2c4914ebd033..315a1a08b57d 100644 --- a/pkg/server/container_create.go +++ b/pkg/server/container_create.go @@ -289,7 +289,7 @@ func (c *criContainerdService) generateContainerSpec(id string, sandboxPid uint3 return nil, err } } else { - if err := addOCIDevices(&g, config.GetDevices()); err != nil { + if err := c.addOCIDevices(&g, config.GetDevices()); err != nil { return nil, fmt.Errorf("failed to set devices mapping %+v: %v", config.GetDevices(), err) } @@ -414,10 +414,10 @@ func clearReadOnly(m *runtimespec.Mount) { } // addDevices set device mapping without privilege. -func addOCIDevices(g *generate.Generator, devs []*runtime.Device) error { +func (c *criContainerdService) addOCIDevices(g *generate.Generator, devs []*runtime.Device) error { spec := g.Spec() for _, device := range devs { - path, err := resolveSymbolicLink(device.HostPath) + path, err := c.os.ResolveSymbolicLink(device.HostPath) if err != nil { return err } @@ -497,7 +497,7 @@ func addOCIBindMounts(g *generate.Generator, mounts []*runtime.Mount, mountLabel } // TODO(random-liu): Add cri-containerd integration test or cri validation test // for this. - src, err := resolveSymbolicLink(src) + src, err := c.os.ResolveSymbolicLink(src) if err != nil { return fmt.Errorf("failed to resolve symlink %q: %v", src, err) } diff --git a/pkg/server/helpers.go b/pkg/server/helpers.go index ebeba75fcc77..d4a66c16b5d7 100644 --- a/pkg/server/helpers.go +++ b/pkg/server/helpers.go @@ -297,19 +297,6 @@ func (c *criContainerdService) ensureImageExists(ctx context.Context, ref string return &newImage, nil } -// resolveSymbolicLink resolves a possbile symlink path. If the path is a symlink, returns resolved -// path; if not, returns the original path. -func resolveSymbolicLink(path string) (string, error) { - info, err := os.Lstat(path) - if err != nil { - return "", err - } - if info.Mode()&os.ModeSymlink != os.ModeSymlink { - return path, nil - } - return filepath.EvalSymlinks(path) -} - // loadCgroup loads the cgroup associated with path if it exists and moves the current process into the cgroup. If the cgroup // is not created it is created and returned. func loadCgroup(cgroupPath string) (cgroups.Cgroup, error) {