Merge pull request #2112 from crosbymichael/temp-mounts
Add temp mount location to manage temp mounts
This commit is contained in:
commit
3b4fcf771a
@ -28,6 +28,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/server"
|
"github.com/containerd/containerd/server"
|
||||||
"github.com/containerd/containerd/sys"
|
"github.com/containerd/containerd/sys"
|
||||||
"github.com/containerd/containerd/version"
|
"github.com/containerd/containerd/version"
|
||||||
@ -111,6 +112,14 @@ func App() *cli.App {
|
|||||||
if err := applyFlags(context, config); err != nil {
|
if err := applyFlags(context, config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// cleanup temp mounts
|
||||||
|
if err := mount.SetTempMountLocation(filepath.Join(config.Root, "tmpmounts")); err != nil {
|
||||||
|
return errors.Wrap(err, "creating temp mount location")
|
||||||
|
}
|
||||||
|
// unmount all temp mounts on boot for the server
|
||||||
|
if err := mount.CleanupTempMounts(0); err != nil {
|
||||||
|
return errors.Wrap(err, "unmounting temp mounts")
|
||||||
|
}
|
||||||
address := config.GRPC.Address
|
address := config.GRPC.Address
|
||||||
if address == "" {
|
if address == "" {
|
||||||
return errors.New("grpc address cannot be empty")
|
return errors.New("grpc address cannot be empty")
|
||||||
|
@ -16,15 +16,6 @@
|
|||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/log"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mount is the lingua franca of containerd. A mount represents a
|
// Mount is the lingua franca of containerd. A mount represents a
|
||||||
// serialized mount syscall. Components either emit or consume mounts.
|
// serialized mount syscall. Components either emit or consume mounts.
|
||||||
type Mount struct {
|
type Mount struct {
|
||||||
@ -47,42 +38,3 @@ func All(mounts []Mount, target string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f.
|
|
||||||
// The mounts are valid during the call to the f.
|
|
||||||
// Finally we will unmount and remove the temp dir regardless of the result of f.
|
|
||||||
func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) error) (err error) {
|
|
||||||
root, uerr := ioutil.TempDir("", "containerd-WithTempMount")
|
|
||||||
if uerr != nil {
|
|
||||||
return errors.Wrapf(uerr, "failed to create temp dir")
|
|
||||||
}
|
|
||||||
// We use Remove here instead of RemoveAll.
|
|
||||||
// The RemoveAll will delete the temp dir and all children it contains.
|
|
||||||
// When the Unmount fails, RemoveAll will incorrectly delete data from
|
|
||||||
// the mounted dir. However, if we use Remove, even though we won't
|
|
||||||
// successfully delete the temp dir and it may leak, we won't loss data
|
|
||||||
// from the mounted dir.
|
|
||||||
// For details, please refer to #1868 #1785.
|
|
||||||
defer func() {
|
|
||||||
if uerr = os.Remove(root); uerr != nil {
|
|
||||||
log.G(ctx).WithError(uerr).WithField("dir", root).Errorf("failed to remove mount temp dir")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// We should do defer first, if not we will not do Unmount when only a part of Mounts are failed.
|
|
||||||
defer func() {
|
|
||||||
if uerr = UnmountAll(root, 0); uerr != nil {
|
|
||||||
uerr = errors.Wrapf(uerr, "failed to unmount %s", root)
|
|
||||||
if err == nil {
|
|
||||||
err = uerr
|
|
||||||
} else {
|
|
||||||
err = errors.Wrap(err, uerr.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if uerr = All(mounts, root); uerr != nil {
|
|
||||||
return errors.Wrapf(uerr, "failed to mount %s", root)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Wrapf(f(root), "mount callback failed on %s", root)
|
|
||||||
}
|
|
||||||
|
50
mount/temp.go
Normal file
50
mount/temp.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tempMountLocation = os.TempDir()
|
||||||
|
|
||||||
|
// WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f.
|
||||||
|
// The mounts are valid during the call to the f.
|
||||||
|
// Finally we will unmount and remove the temp dir regardless of the result of f.
|
||||||
|
func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) error) (err error) {
|
||||||
|
root, uerr := ioutil.TempDir(tempMountLocation, "containerd-mount")
|
||||||
|
if uerr != nil {
|
||||||
|
return errors.Wrapf(uerr, "failed to create temp dir")
|
||||||
|
}
|
||||||
|
// We use Remove here instead of RemoveAll.
|
||||||
|
// The RemoveAll will delete the temp dir and all children it contains.
|
||||||
|
// When the Unmount fails, RemoveAll will incorrectly delete data from
|
||||||
|
// the mounted dir. However, if we use Remove, even though we won't
|
||||||
|
// successfully delete the temp dir and it may leak, we won't loss data
|
||||||
|
// from the mounted dir.
|
||||||
|
// For details, please refer to #1868 #1785.
|
||||||
|
defer func() {
|
||||||
|
if uerr = os.Remove(root); uerr != nil {
|
||||||
|
log.G(ctx).WithError(uerr).WithField("dir", root).Errorf("failed to remove mount temp dir")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// We should do defer first, if not we will not do Unmount when only a part of Mounts are failed.
|
||||||
|
defer func() {
|
||||||
|
if uerr = UnmountAll(root, 0); uerr != nil {
|
||||||
|
uerr = errors.Wrapf(uerr, "failed to unmount %s", root)
|
||||||
|
if err == nil {
|
||||||
|
err = uerr
|
||||||
|
} else {
|
||||||
|
err = errors.Wrap(err, uerr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if uerr = All(mounts, root); uerr != nil {
|
||||||
|
return errors.Wrapf(uerr, "failed to mount %s", root)
|
||||||
|
}
|
||||||
|
return errors.Wrapf(f(root), "mount callback failed on %s", root)
|
||||||
|
}
|
47
mount/temp_unix.go
Normal file
47
mount/temp_unix.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetTempMountLocation sets the temporary mount location
|
||||||
|
func SetTempMountLocation(root string) error {
|
||||||
|
root, err := filepath.Abs(root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(root, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tempMountLocation = root
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanupTempMounts all temp mounts and remove the directories
|
||||||
|
func CleanupTempMounts(flags int) error {
|
||||||
|
mounts, err := Self()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var toUnmount []string
|
||||||
|
for _, m := range mounts {
|
||||||
|
if strings.HasPrefix(m.Mountpoint, tempMountLocation) {
|
||||||
|
toUnmount = append(toUnmount, m.Mountpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(sort.Reverse(sort.StringSlice(toUnmount)))
|
||||||
|
for _, path := range toUnmount {
|
||||||
|
if err := UnmountAll(path, flags); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.Remove(path); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
13
mount/temp_unsupported.go
Normal file
13
mount/temp_unsupported.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
// SetTempMountLocation sets the temporary mount location
|
||||||
|
func SetTempMountLocation(root string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanupTempMounts all temp mounts and remove the directories
|
||||||
|
func CleanupTempMounts(flags int) error {
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user