mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
[refactor] Move task directory destroy logic from alloc_dir.go to task_dir.go (#20006)
* Move task directory destroy logic from alloc_dir to task_dir * Update errors to wrap error cause * Use constants for file permissions * Make multierror handling consistent. * Make helpers for directory creation * Move mount dir unlink to task_dir Unlink method * Make constant for file mode 710 Co-authored-by: Tim Gross <tgross@hashicorp.com> Co-authored-by: Michael Schurter <mschurter@hashicorp.com>
This commit is contained in:
@@ -28,6 +28,18 @@ const (
|
||||
// idUnsupported is what the uid/gid will be set to on platforms (eg
|
||||
// Windows) that don't support integer ownership identifiers.
|
||||
idUnsupported = -1
|
||||
|
||||
// fileMode777 is a constant that represents the file mode rwxrwxrwx
|
||||
fileMode777 = os.FileMode(0o777)
|
||||
|
||||
// fileMode710 is a constant that represents the file mode rwx--x---
|
||||
fileMode710 = os.FileMode(0o710)
|
||||
|
||||
// fileMode755 is a constant that represents the file mode rwxr-xr-x
|
||||
fileMode755 = os.FileMode(0o755)
|
||||
|
||||
// fileMode666 is a constant that represents the file mode rw-rw-rw-
|
||||
fileMode666 = os.FileMode(0o666)
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -65,7 +77,7 @@ var (
|
||||
TaskPrivate = "private"
|
||||
|
||||
// TaskDirs is the set of directories created in each tasks directory.
|
||||
TaskDirs = map[string]os.FileMode{TmpDirName: os.ModeSticky | 0777}
|
||||
TaskDirs = map[string]os.FileMode{TmpDirName: os.ModeSticky | fileMode777}
|
||||
|
||||
// AllocGRPCSocket is the path relative to the task dir root for the
|
||||
// unix socket connected to Consul's gRPC endpoint.
|
||||
@@ -210,7 +222,7 @@ func (d *AllocDir) Snapshot(w io.Writer) error {
|
||||
}
|
||||
hdr, err := tar.FileInfoHeader(fileInfo, link)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating file header: %v", err)
|
||||
return fmt.Errorf("error creating file header: %w", err)
|
||||
}
|
||||
hdr.Name = relPath
|
||||
if err := tw.WriteHeader(hdr); err != nil {
|
||||
@@ -248,7 +260,7 @@ func (d *AllocDir) Snapshot(w io.Writer) error {
|
||||
// anyway.
|
||||
d.logger.Warn("snapshotting failed and unable to write error marker", "error", writeErr)
|
||||
}
|
||||
return fmt.Errorf("failed to snapshot %s: %v", path, err)
|
||||
return fmt.Errorf("failed to snapshot %s: %w", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +285,7 @@ func (d *AllocDir) Move(other Interface, tasks []*structs.Task) error {
|
||||
if fileInfo, err := os.Stat(otherDataDir); fileInfo != nil && err == nil {
|
||||
os.Remove(dataDir) // remove an empty data dir if it exists
|
||||
if err := os.Rename(otherDataDir, dataDir); err != nil {
|
||||
return fmt.Errorf("error moving data dir: %v", err)
|
||||
return fmt.Errorf("error moving data dir: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,13 +298,13 @@ func (d *AllocDir) Move(other Interface, tasks []*structs.Task) error {
|
||||
if fileInfo != nil && err == nil {
|
||||
// TaskDirs haven't been built yet, so create it
|
||||
newTaskDir := filepath.Join(d.AllocDir, task.Name)
|
||||
if err := os.MkdirAll(newTaskDir, 0777); err != nil {
|
||||
return fmt.Errorf("error creating task %q dir: %v", task.Name, err)
|
||||
if err := os.MkdirAll(newTaskDir, fileMode777); err != nil {
|
||||
return fmt.Errorf("error creating task %q dir: %w", task.Name, err)
|
||||
}
|
||||
localDir := filepath.Join(newTaskDir, TaskLocal)
|
||||
os.Remove(localDir) // remove an empty local dir if it exists
|
||||
if err := os.Rename(otherTaskLocal, localDir); err != nil {
|
||||
return fmt.Errorf("error moving task %q local dir: %v", task.Name, err)
|
||||
return fmt.Errorf("error moving task %q local dir: %w", task.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,13 +315,13 @@ func (d *AllocDir) Move(other Interface, tasks []*structs.Task) error {
|
||||
// Destroy tears down previously build directory structure.
|
||||
func (d *AllocDir) Destroy() error {
|
||||
// Unmount all mounted shared alloc dirs.
|
||||
var mErr multierror.Error
|
||||
mErr := new(multierror.Error)
|
||||
if err := d.UnmountAll(); err != nil {
|
||||
mErr.Errors = append(mErr.Errors, err)
|
||||
mErr = multierror.Append(mErr, err)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(d.AllocDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("failed to remove alloc dir %q: %v", d.AllocDir, err))
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("failed to remove alloc dir %q: %w", d.AllocDir, err))
|
||||
}
|
||||
|
||||
// Unset built since the alloc dir has been destroyed.
|
||||
@@ -324,52 +336,10 @@ func (d *AllocDir) UnmountAll() error {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
|
||||
var mErr multierror.Error
|
||||
mErr := new(multierror.Error)
|
||||
for _, dir := range d.TaskDirs {
|
||||
// Check if the directory has the shared alloc mounted.
|
||||
if pathExists(dir.SharedTaskDir) {
|
||||
if err := unlinkDir(dir.SharedTaskDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to unmount shared alloc dir %q: %v", dir.SharedTaskDir, err))
|
||||
} else if err := os.RemoveAll(dir.SharedTaskDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to delete shared alloc dir %q: %v", dir.SharedTaskDir, err))
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(dir.SecretsDir) {
|
||||
if err := removeSecretDir(dir.SecretsDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to remove the secret dir %q: %v", dir.SecretsDir, err))
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(dir.PrivateDir) {
|
||||
if err := removeSecretDir(dir.PrivateDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to remove the private dir %q: %v", dir.PrivateDir, err))
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(dir.MountsAllocDir) {
|
||||
if err := unlinkDir(dir.MountsAllocDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to remove the alloc mounts dir %q: %v", dir.MountsAllocDir, err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(dir.MountsTaskDir) {
|
||||
if err := unlinkDir(dir.MountsTaskDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to remove the alloc mounts task dir %q: %v", dir.MountsTaskDir, err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Unmount dev/ and proc/ have been mounted.
|
||||
if err := dir.unmountSpecialDirs(); err != nil {
|
||||
mErr.Errors = append(mErr.Errors, err)
|
||||
if err := dir.Unmount(); err != nil {
|
||||
mErr = multierror.Append(mErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,27 +349,19 @@ func (d *AllocDir) UnmountAll() error {
|
||||
// Build the directory tree for an allocation.
|
||||
func (d *AllocDir) Build() error {
|
||||
// Make the alloc directory, owned by the nomad process.
|
||||
if err := os.MkdirAll(d.AllocDir, 0755); err != nil {
|
||||
return fmt.Errorf("Failed to make the alloc directory %v: %v", d.AllocDir, err)
|
||||
if err := os.MkdirAll(d.AllocDir, fileMode755); err != nil {
|
||||
return fmt.Errorf("Failed to make the alloc directory %v: %w", d.AllocDir, err)
|
||||
}
|
||||
|
||||
// Make the shared directory and make it available to all user/groups.
|
||||
if err := os.MkdirAll(d.SharedDir, 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make the shared directory have non-root permissions.
|
||||
if err := dropDirPermissions(d.SharedDir, os.ModePerm); err != nil {
|
||||
if err := allocMkdirAll(d.SharedDir, fileMode755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create shared subdirs
|
||||
for _, dir := range SharedAllocDirs {
|
||||
p := filepath.Join(d.SharedDir, dir)
|
||||
if err := os.MkdirAll(p, 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dropDirPermissions(p, os.ModePerm); err != nil {
|
||||
if err := allocMkdirAll(p, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -414,7 +376,7 @@ func (d *AllocDir) Build() error {
|
||||
// List returns the list of files at a path relative to the alloc dir
|
||||
func (d *AllocDir) List(path string) ([]*cstructs.AllocFileInfo, error) {
|
||||
if escapes, err := escapingfs.PathEscapesAllocDir(d.AllocDir, "", path); err != nil {
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %w", err)
|
||||
} else if escapes {
|
||||
return nil, fmt.Errorf("Path escapes the alloc directory")
|
||||
}
|
||||
@@ -444,7 +406,7 @@ func (d *AllocDir) List(path string) ([]*cstructs.AllocFileInfo, error) {
|
||||
// Stat returns information about the file at a path relative to the alloc dir
|
||||
func (d *AllocDir) Stat(path string) (*cstructs.AllocFileInfo, error) {
|
||||
if escapes, err := escapingfs.PathEscapesAllocDir(d.AllocDir, "", path); err != nil {
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %w", err)
|
||||
} else if escapes {
|
||||
return nil, fmt.Errorf("Path escapes the alloc directory")
|
||||
}
|
||||
@@ -494,7 +456,7 @@ func detectContentType(fileInfo os.FileInfo, path string) string {
|
||||
// ReadAt returns a reader for a file at the path relative to the alloc dir
|
||||
func (d *AllocDir) ReadAt(path string, offset int64) (io.ReadCloser, error) {
|
||||
if escapes, err := escapingfs.PathEscapesAllocDir(d.AllocDir, "", path); err != nil {
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %w", err)
|
||||
} else if escapes {
|
||||
return nil, fmt.Errorf("Path escapes the alloc directory")
|
||||
}
|
||||
@@ -520,7 +482,7 @@ func (d *AllocDir) ReadAt(path string, offset int64) (io.ReadCloser, error) {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := f.Seek(offset, 0); err != nil {
|
||||
return nil, fmt.Errorf("can't seek to offset %q: %v", offset, err)
|
||||
return nil, fmt.Errorf("can't seek to offset %q: %w", offset, err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
@@ -529,7 +491,7 @@ func (d *AllocDir) ReadAt(path string, offset int64) (io.ReadCloser, error) {
|
||||
// directory exists. The block can be cancelled with the passed context.
|
||||
func (d *AllocDir) BlockUntilExists(ctx context.Context, path string) (chan error, error) {
|
||||
if escapes, err := escapingfs.PathEscapesAllocDir(d.AllocDir, "", path); err != nil {
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %w", err)
|
||||
} else if escapes {
|
||||
return nil, fmt.Errorf("Path escapes the alloc directory")
|
||||
}
|
||||
@@ -555,7 +517,7 @@ func (d *AllocDir) BlockUntilExists(ctx context.Context, path string) (chan erro
|
||||
// used to clean up the watch.
|
||||
func (d *AllocDir) ChangeEvents(ctx context.Context, path string, curOffset int64) (*watch.FileChanges, error) {
|
||||
if escapes, err := escapingfs.PathEscapesAllocDir(d.AllocDir, "", path); err != nil {
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
|
||||
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %w", err)
|
||||
} else if escapes {
|
||||
return nil, fmt.Errorf("Path escapes the alloc directory")
|
||||
}
|
||||
@@ -583,23 +545,23 @@ func fileCopy(src, dst string, uid, gid int, perm os.FileMode) error {
|
||||
// Do a simple copy.
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't open src file %v: %v", src, err)
|
||||
return fmt.Errorf("Couldn't open src file %v: %w", src, err)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, perm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't create destination file %v: %v", dst, err)
|
||||
return fmt.Errorf("Couldn't create destination file %v: %w", dst, err)
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
if _, err := io.Copy(dstFile, srcFile); err != nil {
|
||||
return fmt.Errorf("Couldn't copy %q to %q: %v", src, dst, err)
|
||||
return fmt.Errorf("Couldn't copy %q to %q: %w", src, dst, err)
|
||||
}
|
||||
|
||||
if uid != idUnsupported && gid != idUnsupported {
|
||||
if err := dstFile.Chown(uid, gid); err != nil {
|
||||
return fmt.Errorf("Couldn't copy %q to %q: %v", src, dst, err)
|
||||
return fmt.Errorf("Couldn't copy %q to %q: %w", src, dst, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,7 +641,7 @@ func splitPath(path string) ([]fileInfo, error) {
|
||||
// flexible permission.
|
||||
uid, gid := idUnsupported, idUnsupported
|
||||
if err != nil {
|
||||
mode = os.ModePerm
|
||||
mode = fileMode777
|
||||
} else {
|
||||
uid, gid = getOwner(fi)
|
||||
mode = fi.Mode()
|
||||
@@ -698,7 +660,7 @@ func splitPath(path string) ([]fileInfo, error) {
|
||||
uid, gid := idUnsupported, idUnsupported
|
||||
fi, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
mode = os.ModePerm
|
||||
mode = fileMode777
|
||||
} else {
|
||||
uid, gid = getOwner(fi)
|
||||
mode = fi.Mode()
|
||||
@@ -721,7 +683,7 @@ func writeError(tw *tar.Writer, allocID string, err error) error {
|
||||
contents := []byte(fmt.Sprintf("Error snapshotting: %v", err))
|
||||
hdr := tar.Header{
|
||||
Name: SnapshotErrorFilename(allocID),
|
||||
Mode: 0666,
|
||||
Mode: int64(fileMode666),
|
||||
Size: int64(len(contents)),
|
||||
AccessTime: SnapshotErrorTime,
|
||||
ChangeTime: SnapshotErrorTime,
|
||||
@@ -736,3 +698,32 @@ func writeError(tw *tar.Writer, allocID string, err error) error {
|
||||
_, err = tw.Write(contents)
|
||||
return err
|
||||
}
|
||||
|
||||
// allocMkdirAll creates a directory and sets the permissions to the passed
|
||||
// value. It also sets the owner of the directory to "nobody" on systems that
|
||||
// allow.
|
||||
func allocMkdirAll(path string, perms os.FileMode) error {
|
||||
// Create the directory
|
||||
if err := os.MkdirAll(path, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
// Update the access permissions on the directory
|
||||
if err := dropDirPermissions(path, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocMakeSecretsDir creates a directory for sensitive items such as secrets.
|
||||
// When possible it uses a tmpfs or some other method to prevent it from
|
||||
// persisting to actual disk.
|
||||
func allocMakeSecretsDir(path string, perms os.FileMode) error {
|
||||
// Create the private directory
|
||||
if err := createSecretDir(path); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dropDirPermissions(path, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func unlinkDir(dir string) error {
|
||||
|
||||
// createSecretDir creates the secrets dir folder at the given path
|
||||
func createSecretDir(dir string) error {
|
||||
return os.MkdirAll(dir, 0777)
|
||||
return os.MkdirAll(dir, fileMode777)
|
||||
}
|
||||
|
||||
// removeSecretDir removes the secrets dir folder
|
||||
|
||||
@@ -20,7 +20,7 @@ func unlinkDir(dir string) error {
|
||||
|
||||
// createSecretDir creates the secrets dir folder at the given path
|
||||
func createSecretDir(dir string) error {
|
||||
return os.MkdirAll(dir, 0777)
|
||||
return os.MkdirAll(dir, fileMode777)
|
||||
}
|
||||
|
||||
// removeSecretDir removes the secrets dir folder
|
||||
|
||||
@@ -26,7 +26,7 @@ const (
|
||||
// linkDir bind mounts src to dst as Linux doesn't support hardlinking
|
||||
// directories.
|
||||
func linkDir(src, dst string) error {
|
||||
if err := os.MkdirAll(dst, 0777); err != nil {
|
||||
if err := os.MkdirAll(dst, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func unlinkDir(dir string) error {
|
||||
func createSecretDir(dir string) error {
|
||||
// Only mount the tmpfs if we are root
|
||||
if unix.Geteuid() == 0 {
|
||||
if err := os.MkdirAll(dir, 0777); err != nil {
|
||||
if err := os.MkdirAll(dir, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func createSecretDir(dir string) error {
|
||||
}
|
||||
|
||||
// Create the marker file so we don't try to mount more than once
|
||||
f, err := os.OpenFile(marker, os.O_RDWR|os.O_CREATE, 0666)
|
||||
f, err := os.OpenFile(marker, os.O_RDWR|os.O_CREATE, fileMode666)
|
||||
if err != nil {
|
||||
// Hard fail since if this fails something is really wrong
|
||||
return err
|
||||
@@ -88,7 +88,7 @@ func createSecretDir(dir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.MkdirAll(dir, 0777)
|
||||
return os.MkdirAll(dir, fileMode777)
|
||||
}
|
||||
|
||||
// createSecretDir removes the secrets dir folder
|
||||
|
||||
@@ -20,7 +20,7 @@ func unlinkDir(dir string) error {
|
||||
|
||||
// createSecretDir creates the secrets dir folder at the given path
|
||||
func createSecretDir(dir string) error {
|
||||
return os.MkdirAll(dir, 0777)
|
||||
return os.MkdirAll(dir, fileMode777)
|
||||
}
|
||||
|
||||
// removeSecretDir removes the secrets dir folder
|
||||
|
||||
@@ -21,7 +21,7 @@ func unlinkDir(dir string) error {
|
||||
// createSecretDir creates the secrets dir folder at the given path
|
||||
func createSecretDir(dir string) error {
|
||||
// TODO solaris has support for tmpfs so use that
|
||||
return os.MkdirAll(dir, 0777)
|
||||
return os.MkdirAll(dir, fileMode777)
|
||||
}
|
||||
|
||||
// removeSecretDir removes the secrets dir folder
|
||||
|
||||
@@ -34,8 +34,8 @@ var (
|
||||
// dropDirPermissions gives full access to a directory to all users and sets
|
||||
// the owner to nobody.
|
||||
func dropDirPermissions(path string, desired os.FileMode) error {
|
||||
if err := os.Chmod(path, desired|0777); err != nil {
|
||||
return fmt.Errorf("Chmod(%v) failed: %v", path, err)
|
||||
if err := os.Chmod(path, desired|fileMode777); err != nil {
|
||||
return fmt.Errorf("Chmod(%v) failed: %w", path, err)
|
||||
}
|
||||
|
||||
// Can't change owner if not root.
|
||||
@@ -59,7 +59,7 @@ func dropDirPermissions(path string, desired os.FileMode) error {
|
||||
}
|
||||
|
||||
if err := os.Chown(path, uid, gid); err != nil {
|
||||
return fmt.Errorf("Couldn't change owner/group of %v to (uid: %v, gid: %v): %v", path, uid, gid, err)
|
||||
return fmt.Errorf("Couldn't change owner/group of %v to (uid: %v, gid: %v): %w", path, uid, gid, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -69,7 +69,7 @@ func dropDirPermissions(path string, desired os.FileMode) error {
|
||||
func getUid(u *user.User) (int, error) {
|
||||
uid, err := strconv.Atoi(u.Uid)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Unable to convert Uid to an int: %v", err)
|
||||
return 0, fmt.Errorf("Unable to convert Uid to an int: %w", err)
|
||||
}
|
||||
|
||||
return uid, nil
|
||||
@@ -79,7 +79,7 @@ func getUid(u *user.User) (int, error) {
|
||||
func getGid(u *user.User) (int, error) {
|
||||
gid, err := strconv.Atoi(u.Gid)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Unable to convert Gid to an int: %v", err)
|
||||
return 0, fmt.Errorf("Unable to convert Gid to an int: %w", err)
|
||||
}
|
||||
|
||||
return gid, nil
|
||||
|
||||
@@ -39,7 +39,7 @@ func unlinkDir(dir string) error {
|
||||
|
||||
// createSecretDir creates the secrets dir folder at the given path
|
||||
func createSecretDir(dir string) error {
|
||||
return os.MkdirAll(dir, 0777)
|
||||
return os.MkdirAll(dir, fileMode777)
|
||||
}
|
||||
|
||||
// removeSecretDir removes the secrets dir folder
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/go-set/v2"
|
||||
"github.com/hashicorp/nomad/helper/users/dynamic"
|
||||
"github.com/hashicorp/nomad/plugins/drivers/fsisolation"
|
||||
@@ -107,32 +108,19 @@ func (d *AllocDir) newTaskDir(taskName string) *TaskDir {
|
||||
// allows skipping chroot creation if the caller knows it has already been
|
||||
// done. client.alloc_dir will be skipped.
|
||||
func (t *TaskDir) Build(fsi fsisolation.Mode, chroot map[string]string, username string) error {
|
||||
if err := os.MkdirAll(t.Dir, 0777); err != nil {
|
||||
if err := allocMkdirAll(t.Dir, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make the task directory have non-root permissions.
|
||||
if err := dropDirPermissions(t.Dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a local directory that each task can use.
|
||||
if err := os.MkdirAll(t.LocalDir, 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := dropDirPermissions(t.LocalDir, os.ModePerm); err != nil {
|
||||
if err := allocMkdirAll(t.LocalDir, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the directories that should be in every task.
|
||||
for dir, perms := range TaskDirs {
|
||||
absdir := filepath.Join(t.Dir, dir)
|
||||
if err := os.MkdirAll(absdir, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := dropDirPermissions(absdir, perms); err != nil {
|
||||
if err := allocMkdirAll(absdir, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -146,26 +134,18 @@ func (t *TaskDir) Build(fsi fsisolation.Mode, chroot map[string]string, username
|
||||
empty, _ := pathEmpty(t.SharedTaskDir)
|
||||
if !pathExists(t.SharedTaskDir) || empty {
|
||||
if err := linkDir(t.SharedAllocDir, t.SharedTaskDir); err != nil {
|
||||
return fmt.Errorf("Failed to mount shared directory for task: %v", err)
|
||||
return fmt.Errorf("Failed to mount shared directory for task: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the secret directory
|
||||
if err := createSecretDir(t.SecretsDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := dropDirPermissions(t.SecretsDir, os.ModePerm); err != nil {
|
||||
if err := allocMakeSecretsDir(t.SecretsDir, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the private directory
|
||||
if err := createSecretDir(t.PrivateDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := dropDirPermissions(t.PrivateDir, os.ModePerm); err != nil {
|
||||
if err := allocMakeSecretsDir(t.PrivateDir, fileMode777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -185,7 +165,7 @@ func (t *TaskDir) Build(fsi fsisolation.Mode, chroot map[string]string, username
|
||||
|
||||
// create the task unique directory under the client mounts path
|
||||
parent := filepath.Dir(t.MountsAllocDir)
|
||||
if err = os.MkdirAll(parent, 0o710); err != nil {
|
||||
if err = os.MkdirAll(parent, fileMode710); err != nil {
|
||||
return fmt.Errorf("Failed to create task mount directory: %v", err)
|
||||
}
|
||||
if err = os.Chown(parent, uid, gid); err != nil {
|
||||
@@ -193,8 +173,8 @@ func (t *TaskDir) Build(fsi fsisolation.Mode, chroot map[string]string, username
|
||||
}
|
||||
|
||||
// create the task and alloc mount points
|
||||
mountDir(t.AllocDir, t.MountsAllocDir, uid, gid, 0o710)
|
||||
mountDir(t.Dir, t.MountsTaskDir, uid, gid, 0o710)
|
||||
mountDir(t.AllocDir, t.MountsAllocDir, uid, gid, fileMode710)
|
||||
mountDir(t.Dir, t.MountsTaskDir, uid, gid, fileMode710)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -225,7 +205,7 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
|
||||
// Embedding a single file
|
||||
if !s.IsDir() {
|
||||
if err := createDir(t.Dir, filepath.Dir(dest)); err != nil {
|
||||
return fmt.Errorf("Couldn't create destination directory %v: %v", dest, err)
|
||||
return fmt.Errorf("Couldn't create destination directory %v: %w", dest, err)
|
||||
}
|
||||
|
||||
// Copy the file.
|
||||
@@ -242,19 +222,19 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
|
||||
destDir := filepath.Join(t.Dir, dest)
|
||||
|
||||
if err := createDir(t.Dir, dest); err != nil {
|
||||
return fmt.Errorf("Couldn't create destination directory %v: %v", destDir, err)
|
||||
return fmt.Errorf("Couldn't create destination directory %v: %w", destDir, err)
|
||||
}
|
||||
|
||||
// Enumerate the files in source.
|
||||
dirEntries, err := os.ReadDir(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't read directory %v: %v", source, err)
|
||||
return fmt.Errorf("Couldn't read directory %v: %w", source, err)
|
||||
}
|
||||
|
||||
for _, fileEntry := range dirEntries {
|
||||
entry, err := fileEntry.Info()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't read the file information %v: %v", entry, err)
|
||||
return fmt.Errorf("Couldn't read the file information %v: %w", entry, err)
|
||||
}
|
||||
hostEntry := filepath.Join(source, entry.Name())
|
||||
taskEntry := filepath.Join(destDir, filepath.Base(hostEntry))
|
||||
@@ -277,13 +257,13 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
|
||||
|
||||
link, err := os.Readlink(hostEntry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't resolve symlink for %v: %v", source, err)
|
||||
return fmt.Errorf("Couldn't resolve symlink for %v: %w", source, err)
|
||||
}
|
||||
|
||||
if err := os.Symlink(link, taskEntry); err != nil {
|
||||
// Symlinking twice
|
||||
if err.(*os.LinkError).Err.Error() != "file exists" {
|
||||
return fmt.Errorf("Couldn't create symlink: %v", err)
|
||||
return fmt.Errorf("Couldn't create symlink: %w", err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
@@ -303,3 +283,55 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmount or delete task directories. Returns all errors as a multierror.
|
||||
func (t *TaskDir) Unmount() error {
|
||||
mErr := new(multierror.Error)
|
||||
|
||||
// Check if the directory has the shared alloc mounted.
|
||||
if pathExists(t.SharedTaskDir) {
|
||||
if err := unlinkDir(t.SharedTaskDir); err != nil {
|
||||
mErr = multierror.Append(mErr,
|
||||
fmt.Errorf("failed to unmount shared alloc dir %q: %w", t.SharedTaskDir, err))
|
||||
} else if err := os.RemoveAll(t.SharedTaskDir); err != nil {
|
||||
mErr = multierror.Append(mErr,
|
||||
fmt.Errorf("failed to delete shared alloc dir %q: %w", t.SharedTaskDir, err))
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(t.SecretsDir) {
|
||||
if err := removeSecretDir(t.SecretsDir); err != nil {
|
||||
mErr = multierror.Append(mErr,
|
||||
fmt.Errorf("failed to remove the secret dir %q: %w", t.SecretsDir, err))
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(t.PrivateDir) {
|
||||
if err := removeSecretDir(t.PrivateDir); err != nil {
|
||||
mErr = multierror.Append(mErr,
|
||||
fmt.Errorf("failed to remove the private dir %q: %w", t.PrivateDir, err))
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(t.MountsAllocDir) {
|
||||
if err := unlinkDir(t.MountsAllocDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to remove the alloc mounts dir %q: %w", t.MountsAllocDir, err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if pathExists(t.MountsTaskDir) {
|
||||
if err := unlinkDir(t.MountsTaskDir); err != nil {
|
||||
mErr.Errors = append(mErr.Errors,
|
||||
fmt.Errorf("failed to remove the alloc mounts task dir %q: %w", t.MountsTaskDir, err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Unmount dev/ and proc/ have been mounted.
|
||||
if err := t.unmountSpecialDirs(); err != nil {
|
||||
mErr = multierror.Append(mErr, err)
|
||||
}
|
||||
return mErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ import (
|
||||
// error is returned if the directories do not exist or have already been
|
||||
// unmounted.
|
||||
func (t *TaskDir) unmountSpecialDirs() error {
|
||||
errs := new(multierror.Error)
|
||||
mErr := new(multierror.Error)
|
||||
dev := filepath.Join(t.Dir, "dev")
|
||||
if pathExists(dev) {
|
||||
if err := unlinkDir(dev); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("Failed to unmount dev %q: %v", dev, err))
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("Failed to unmount dev %q: %w", dev, err))
|
||||
} else if err := os.RemoveAll(dev); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("Failed to delete dev directory %q: %v", dev, err))
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("Failed to delete dev directory %q: %w", dev, err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ func (t *TaskDir) unmountSpecialDirs() error {
|
||||
proc := filepath.Join(t.Dir, "proc")
|
||||
if pathExists(proc) {
|
||||
if err := unlinkDir(proc); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("Failed to unmount proc %q: %v", proc, err))
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("Failed to unmount proc %q: %w", proc, err))
|
||||
} else if err := os.RemoveAll(proc); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("Failed to delete proc directory %q: %v", dev, err))
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("Failed to delete proc directory %q: %w", dev, err))
|
||||
}
|
||||
}
|
||||
|
||||
return errs.ErrorOrNil()
|
||||
return mErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user