Skip to content

Commit

Permalink
Merge pull request microsoft#1057 from dcantah/jobcontainer-volume
Browse files Browse the repository at this point in the history
Add volume mount support for job containers
  • Loading branch information
dcantah authored Jul 15, 2021
2 parents 3edb2d5 + 267fd4c commit 8192b82
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 1 deletion.
6 changes: 5 additions & 1 deletion jobcontainers/jobcontainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ func Create(ctx context.Context, id string, s *specs.Spec) (_ cow.Container, _ *
layers := layers.NewImageLayers(nil, "", s.Windows.LayerFolders, sandboxPath, false)
r.SetLayers(layers)

if err := setupMounts(s, container.sandboxMount); err != nil {
return nil, nil, err
}

volumeGUIDRegex := `^\\\\\?\\(Volume)\{{0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}\}(|\\)$`
if matched, err := regexp.MatchString(volumeGUIDRegex, s.Root.Path); !matched || err != nil {
return nil, nil, fmt.Errorf(`invalid container spec - Root.Path '%s' must be a volume GUID path in the format '\\?\Volume{GUID}\'`, s.Root.Path)
Expand Down Expand Up @@ -524,7 +528,7 @@ func systemProcessInformation() ([]*winapi.SYSTEM_PROCESS_INFORMATION, error) {
var (
systemProcInfo *winapi.SYSTEM_PROCESS_INFORMATION
procInfos []*winapi.SYSTEM_PROCESS_INFORMATION
// This happens to be the buffer size hcs uses but there's no really no hard need to keep it
// This happens to be the buffer size hcs uses but there's really no hard need to keep it
// the same, it's just a sane default.
size = uint32(1024 * 512)
bounds uintptr
Expand Down
56 changes: 56 additions & 0 deletions jobcontainers/mounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package jobcontainers

import (
"fmt"
"os"
"path/filepath"
"strings"

specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)

// namedPipePath returns true if the given path is to a named pipe.
func isnamedPipePath(p string) bool {
return strings.HasPrefix(p, `\\.\pipe\`)
}

// Strip the drive letter (if there is one) so we don't end up with "%CONTAINER_SANDBOX_MOUNT_POINT%"\C:\path\to\mount
func stripDriveLetter(name string) string {
// Remove drive letter
if len(name) == 2 && name[1] == ':' {
name = "."
} else if len(name) > 2 && name[1] == ':' {
name = name[2:]
}
return name
}

// setupMounts adds the custom mounts requested in the OCI runtime spec. Mounts are a bit funny as you already have
// access to everything on the host, so just symlink in whatever was requested to the path where the container volume
// is mounted. At least then the mount can be accessed from a path relative to the default working directory/where the volume
// is.
func setupMounts(spec *specs.Spec, sandboxVolumePath string) error {
for _, mount := range spec.Mounts {
if mount.Destination == "" || mount.Source == "" {
return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
}

if isnamedPipePath(mount.Source) {
return errors.New("named pipe mounts not supported for job containers - interact with the pipe directly")
}

fullCtrPath := filepath.Join(sandboxVolumePath, stripDriveLetter(mount.Destination))
// Make sure all of the dirs leading up to the full path exist.
strippedCtrPath := filepath.Dir(fullCtrPath)
if err := os.MkdirAll(strippedCtrPath, 0777); err != nil {
return errors.Wrap(err, "failed to make directory for job container mount")
}

if err := os.Symlink(mount.Source, fullCtrPath); err != nil {
return errors.Wrap(err, "failed to setup mount for job container")
}
}

return nil
}
21 changes: 21 additions & 0 deletions jobcontainers/mounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package jobcontainers

import (
"testing"

specs "github.com/opencontainers/runtime-spec/specs-go"
)

func TestNamePipeDeny(t *testing.T) {
s := &specs.Spec{
Mounts: []specs.Mount{
{
Destination: "/path/in/container",
Source: `\\.\pipe\dummy\path`,
},
},
}
if err := setupMounts(s, "/test"); err == nil {
t.Fatal("expected named pipe mount validation to fail for job container")
}
}

0 comments on commit 8192b82

Please sign in to comment.