-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mount special filesystem 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.
- Loading branch information
1 parent
a56ecc6
commit 9dbbedf
Showing
5 changed files
with
268 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,98 @@ | ||
package runner | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
|
||
"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 open(buildDirectory filesystem.Directory, inputRootDirectory string) (filesystem.DirectoryCloser, error) { | ||
// TODO(nils): How to best open the input root `Directory` | ||
// It must be a `localDirectory`, but outer directories can be `lazyDirectory`. | ||
// NB: We iterate over Directory, as the initial buildDirectory is not a DirectoryCloser. | ||
iterator := buildDirectory | ||
var dir filesystem.DirectoryCloser | ||
|
||
parts := strings.Split(inputRootDirectory, "/") | ||
if len(parts) == 0 { | ||
return nil, status.Error(codes.FailedPrecondition, "Unexpected empty inputRootDirectory") | ||
} | ||
for i, segment := range parts { | ||
var err error | ||
component, ok := path.NewComponent(segment) | ||
if !ok { | ||
return nil, status.Errorf(codes.InvalidArgument, "Directory path segment %#v has an invalid name", segment) | ||
} | ||
dir, err = iterator.EnterDirectory(component) | ||
if err != nil { | ||
return nil, status.Errorf(codes.FailedPrecondition, "Could not enter directory component %#v in %#v", segment, buildDirectory) | ||
} | ||
if i < len(parts)-1 { | ||
defer dir.Close() | ||
} | ||
|
||
iterator = dir.(filesystem.Directory) | ||
} | ||
return dir, nil | ||
} | ||
|
||
func (r *mountingRunner) Run(ctx context.Context, request *runner_pb.RunRequest) (response *runner_pb.RunResponse, err error) { | ||
root, err := open(r.buildDirectory, request.InputRootDirectory) | ||
if err != nil { | ||
return nil, status.Errorf(codes.FailedPrecondition, "Could not enter input root directory %#v", request.InputRootDirectory) | ||
} | ||
defer root.Close() | ||
|
||
mountpoint, ok := path.NewComponent(r.mount.Mountpoint) | ||
if !ok { | ||
return nil, status.Errorf(codes.InvalidArgument, "Mountpoint %#v has an invalid name", r.mount.Mountpoint) | ||
} | ||
if err := root.Mount(mountpoint, r.mount.Source, r.mount.FilesystemType); err != nil { | ||
return nil, util.StatusWrapf(err, "Failed to mount %#v in the input root", r.mount) | ||
} | ||
|
||
response, err = r.base.Run(ctx, request) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// TODO: is `root` open here or do we need to open it again? | ||
if err2 := root.Unmount(mountpoint); err2 != nil { | ||
err = util.StatusFromMultiple([]error{ | ||
err, | ||
util.StatusWrap(err2, "Failed to unmount %#v in the input root"), | ||
}) | ||
} | ||
|
||
return response, nil | ||
} | ||
|
||
func (r *mountingRunner) CheckReadiness(ctx context.Context, request *runner_pb.CheckReadinessRequest) (*emptypb.Empty, error) { | ||
return r.base.CheckReadiness(ctx, request) | ||
} |