-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mount special filesystems in chroot runners
This can be used to mount special filesystems like '/proc' and '/sys' in the input root of actions if 'chroot' is enabled. The filesystems are required for many tools to work. Solves: #115
- Loading branch information
1 parent
fdbe722
commit 07ffd9d
Showing
6 changed files
with
373 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package runner | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/buildbarn/bb-remote-execution/pkg/proto/configuration/bb_runner" | ||
runner_pb "github.com/buildbarn/bb-remote-execution/pkg/proto/runner" | ||
"github.com/buildbarn/bb-storage/pkg/filesystem" | ||
"github.com/buildbarn/bb-storage/pkg/filesystem/path" | ||
"github.com/buildbarn/bb-storage/pkg/util" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"google.golang.org/protobuf/types/known/emptypb" | ||
) | ||
|
||
type mountingRunner struct { | ||
base runner_pb.RunnerServer | ||
buildDirectory filesystem.Directory | ||
mount *bb_runner.InputMountOptions | ||
} | ||
|
||
// NewMountingRunner is a decorator for Runner | ||
// that mounts `mount` before running a build action. | ||
// | ||
// This decorator can be used for chroot runners | ||
// that must mount special filesystems into the input root. | ||
func NewMountingRunner(base runner_pb.RunnerServer, buildDirectory filesystem.Directory, mount *bb_runner.InputMountOptions) runner_pb.RunnerServer { | ||
return &mountingRunner{ | ||
buildDirectory: buildDirectory, | ||
mount: mount, | ||
base: base, | ||
} | ||
} | ||
|
||
func (r *mountingRunner) Run(ctx context.Context, request *runner_pb.RunRequest) (response *runner_pb.RunResponse, err error) { | ||
rootResolver := buildDirectoryPathResolver{ | ||
stack: util.NewNonEmptyStack(filesystem.NopDirectoryCloser(r.buildDirectory)), | ||
} | ||
defer rootResolver.closeAll() | ||
if err := path.Resolve(request.InputRootDirectory, path.NewRelativeScopeWalker(&rootResolver)); err != nil { | ||
return nil, util.StatusWrap(err, "Invalid input root.") | ||
} | ||
|
||
inputRoot := rootResolver.stack.Peek() | ||
terminal := rootResolver.TerminalName | ||
if terminal != nil { | ||
inputRoot, err = inputRoot.EnterDirectory(*terminal) | ||
if err != nil { | ||
return nil, util.StatusWrap(err, "Invalid input root.") | ||
} | ||
} | ||
|
||
defer inputRoot.Close() | ||
|
||
mountResolver := buildDirectoryPathResolver{ | ||
stack: util.NewNonEmptyStack(filesystem.NopDirectoryCloser(inputRoot)), | ||
} | ||
defer mountResolver.closeAll() | ||
if err := path.Resolve(r.mount.Mountpoint, path.NewRelativeScopeWalker(&mountResolver)); err != nil { | ||
return nil, util.StatusWrap(err, "Invalid mountpoint directory path.") | ||
} | ||
|
||
mountDir := mountResolver.stack.Peek() | ||
defer mountDir.Close() | ||
if mountResolver.TerminalName == nil { | ||
return nil, status.Errorf(codes.InvalidArgument, "Could not resolve mountpoint basename: %#v", r.mount.Mountpoint) | ||
} | ||
|
||
mountname := *mountResolver.TerminalName | ||
if err := mountDir.Mount(mountname, r.mount.Source, r.mount.FilesystemType); err != nil { | ||
return nil, util.StatusWrapf(err, "Failed to mount %#v in the input root", r.mount.Mountpoint) | ||
} | ||
|
||
// We only need the mounting directory file descriptor open. | ||
rootResolver.closeAll() | ||
// Already peeked the mounting directory | ||
// we must now pop it to save it from the close iteration. | ||
maybe, ok := mountResolver.stack.PopSingle() | ||
if ok { | ||
// PopSingle does not return anything if it is the initial element in the stack, | ||
// which we got from Peek earlier. | ||
defer maybe.Close() | ||
mountDir = maybe | ||
} | ||
mountResolver.closeAll() | ||
|
||
response, err = r.base.Run(ctx, request) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if err2 := mountDir.Unmount(mountname); err2 != nil { | ||
err = util.StatusFromMultiple([]error{ | ||
err, | ||
util.StatusWrapf(err2, "Failed to unmount %#v in the input root", r.mount.Mountpoint), | ||
}) | ||
} | ||
|
||
return response, nil | ||
} | ||
|
||
func (r *mountingRunner) CheckReadiness(ctx context.Context, request *runner_pb.CheckReadinessRequest) (*emptypb.Empty, error) { | ||
return r.base.CheckReadiness(ctx, request) | ||
} |
Oops, something went wrong.