...
1
2
3 package jobcontainers
4
5 import (
6 "context"
7 "fmt"
8 "os"
9 "path/filepath"
10 "strings"
11
12 "github.com/Microsoft/hcsshim/internal/layers"
13 "github.com/Microsoft/hcsshim/internal/log"
14 "github.com/Microsoft/hcsshim/internal/logfields"
15 specs "github.com/opencontainers/runtime-spec/specs-go"
16 "github.com/pkg/errors"
17 "github.com/sirupsen/logrus"
18 )
19
20
21 func isnamedPipePath(p string) bool {
22 return strings.HasPrefix(p, `\\.\pipe\`)
23 }
24
25
26 func stripDriveLetter(name string) string {
27
28 if len(name) == 2 && name[1] == ':' {
29 name = "."
30 } else if len(name) > 2 && name[1] == ':' {
31 name = name[2:]
32 }
33 return name
34 }
35
36
37
38
39
40
41 func fallbackMountSetup(spec *specs.Spec, sandboxVolumePath string) error {
42 for _, mount := range spec.Mounts {
43 if mount.Destination == "" || mount.Source == "" {
44 return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
45 }
46
47 if isnamedPipePath(mount.Source) {
48 return errors.New("named pipe mounts not supported for job containers - interact with the pipe directly")
49 }
50
51 fullCtrPath := filepath.Join(sandboxVolumePath, stripDriveLetter(mount.Destination))
52
53 strippedCtrPath := filepath.Dir(fullCtrPath)
54 if err := os.MkdirAll(strippedCtrPath, 0777); err != nil {
55 return errors.Wrap(err, "failed to make directory for job container mount")
56 }
57
58 if err := os.Symlink(mount.Source, fullCtrPath); err != nil {
59 return errors.Wrap(err, "failed to setup mount for job container")
60 }
61 }
62 return nil
63 }
64
65
66
67
68 func (c *JobContainer) setupMounts(ctx context.Context, spec *specs.Spec) error {
69 mountedDirPath, err := os.MkdirTemp("", "jobcontainer")
70 if err != nil {
71 return err
72 }
73 defer os.RemoveAll(mountedDirPath)
74 mountedDirPath += "\\"
75
76
77
78
79
80
81
82
83
84
85
86
87 if err := layers.MountSandboxVolume(ctx, mountedDirPath, c.spec.Root.Path); err != nil {
88 return err
89 }
90
91 for _, mount := range spec.Mounts {
92 if mount.Destination == "" || mount.Source == "" {
93 return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
94 }
95
96 if isnamedPipePath(mount.Source) {
97 return errors.New("named pipe mounts not supported for job containers - interact with the pipe directly")
98 }
99
100
101
102
103 if _, err := os.Stat(mount.Destination); err == nil {
104 log.G(ctx).WithFields(logrus.Fields{
105 logfields.ContainerID: c.id,
106 "mountSource": mount.Source,
107 "mountDestination": mount.Destination,
108 }).Warn("job container mount destination exists and will be shadowed")
109 }
110
111 readOnly := false
112 for _, o := range mount.Options {
113 if strings.ToLower(o) == "ro" {
114 readOnly = true
115 }
116 }
117
118 if err := c.job.ApplyFileBinding(mount.Destination, mount.Source, readOnly); err != nil {
119 return err
120 }
121
122
123
124 fullCtrPath := filepath.Join(mountedDirPath, stripDriveLetter(mount.Destination))
125
126 strippedCtrPath := filepath.Dir(fullCtrPath)
127 if err := os.MkdirAll(strippedCtrPath, 0777); err != nil {
128 return fmt.Errorf("failed to make directory for job container mount: %w", err)
129 }
130
131
132 if err := os.Symlink(mount.Source, fullCtrPath); err != nil {
133 log.G(ctx).WithError(err).Warnf("failed to setup symlink from %s to containers rootfs at %s", mount.Source, fullCtrPath)
134 }
135 }
136
137 return layers.RemoveSandboxMountPoint(ctx, mountedDirPath)
138 }
139
View as plain text