55 "io"
66 "os"
77 "path/filepath"
8- "runtime"
98 "sync"
109 "syscall"
1110 "time"
@@ -17,19 +16,13 @@ import (
1716 "github.com/containerd/containerd"
1817 "github.com/containerd/containerd/cio"
1918 "github.com/containerd/containerd/mount"
20- containerdoci "github.com/containerd/containerd/oci"
21- "github.com/containerd/continuity/fs"
22- "github.com/docker/docker/pkg/idtools"
2319 "github.com/moby/buildkit/executor"
2420 "github.com/moby/buildkit/executor/oci"
2521 resourcestypes "github.com/moby/buildkit/executor/resources/types"
2622 gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
2723 "github.com/moby/buildkit/identity"
28- "github.com/moby/buildkit/snapshot"
2924 "github.com/moby/buildkit/solver/pb"
3025 "github.com/moby/buildkit/util/network"
31- rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
32- "github.com/opencontainers/runtime-spec/specs-go"
3326 "github.com/pkg/errors"
3427)
3528
@@ -39,7 +32,7 @@ type containerdExecutor struct {
3932 networkProviders map [pb.NetMode ]network.Provider
4033 cgroupParent string
4134 dnsConfig * oci.DNSConfig
42- running map [string ]chan error
35+ running map [string ]* containerState
4336 mu sync.Mutex
4437 apparmorProfile string
4538 selinux bool
@@ -72,23 +65,36 @@ func New(client *containerd.Client, root, cgroup string, networkProviders map[pb
7265 networkProviders : networkProviders ,
7366 cgroupParent : cgroup ,
7467 dnsConfig : dnsConfig ,
75- running : make (map [string ]chan error ),
68+ running : make (map [string ]* containerState ),
7669 apparmorProfile : apparmorProfile ,
7770 selinux : selinux ,
7871 traceSocket : traceSocket ,
7972 rootless : rootless ,
8073 }
8174}
8275
76+ type containerState struct {
77+ done chan error
78+ // On linux the rootfsPath is used to ensure the CWD exists, to fetch user information
79+ // and as a bind mount for the root FS of the container.
80+ rootfsPath string
81+ // On Windows we need to use the root mounts to achieve the same thing that Linux does
82+ // with rootfsPath. So we save both in details.
83+ rootMounts []mount.Mount
84+ }
85+
8386func (w * containerdExecutor ) Run (ctx context.Context , id string , root executor.Mount , mounts []executor.Mount , process executor.ProcessInfo , started chan <- struct {}) (rec resourcestypes.Recorder , err error ) {
8487 if id == "" {
8588 id = identity .NewID ()
8689 }
8790
8891 startedOnce := sync.Once {}
8992 done := make (chan error , 1 )
93+ details := & containerState {
94+ done : done ,
95+ }
9096 w .mu .Lock ()
91- w .running [id ] = done
97+ w .running [id ] = details
9298 w .mu .Unlock ()
9399 defer func () {
94100 w .mu .Lock ()
@@ -104,61 +110,19 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
104110 }()
105111
106112 meta := process .Meta
107-
108- resolvConf , err := oci .GetResolvConf (ctx , w .root , nil , w .dnsConfig )
109- if err != nil {
110- return nil , err
111- }
112-
113- hostsFile , clean , err := oci .GetHostsFile (ctx , w .root , meta .ExtraHosts , nil , meta .Hostname )
114- if err != nil {
115- return nil , err
116- }
117- if clean != nil {
118- defer clean ()
119- }
120-
121- mountable , err := root .Src .Mount (ctx , false )
122- if err != nil {
123- return nil , err
124- }
125-
126- rootMounts , release , err := mountable .Mount ()
113+ resolvConf , hostsFile , releasers , err := w .prepareExecutionEnv (ctx , root , mounts , meta , details )
127114 if err != nil {
128115 return nil , err
129116 }
130- if release != nil {
131- defer release ()
132- }
133117
134- lm := snapshot .LocalMounterWithMounts (rootMounts )
135- rootfsPath , err := lm .Mount ()
136- if err != nil {
137- return nil , err
118+ if releasers != nil {
119+ defer releasers ()
138120 }
139- defer lm .Unmount ()
140- defer executor .MountStubsCleaner (ctx , rootfsPath , mounts , meta .RemoveMountStubsRecursive )()
141121
142- uid , gid , sgids , err := oci .GetUser (rootfsPath , meta .User )
143- if err != nil {
122+ if err := w .ensureCWD (ctx , details , meta ); err != nil {
144123 return nil , err
145124 }
146125
147- identity := idtools.Identity {
148- UID : int (uid ),
149- GID : int (gid ),
150- }
151-
152- newp , err := fs .RootPath (rootfsPath , meta .Cwd )
153- if err != nil {
154- return nil , errors .Wrapf (err , "working dir %s points to invalid target" , newp )
155- }
156- if _ , err := os .Stat (newp ); err != nil {
157- if err := idtools .MkdirAllAndChown (newp , 0755 , identity ); err != nil {
158- return nil , errors .Wrapf (err , "failed to create working directory %s" , newp )
159- }
160- }
161-
162126 provider , ok := w .networkProviders [meta .NetMode ]
163127 if ! ok {
164128 return nil , errors .Errorf ("unknown network mode %s" , meta .NetMode )
@@ -173,22 +137,12 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
173137 bklog .G (ctx ).Info ("enabling HostNetworking" )
174138 }
175139
176- opts := []containerdoci.SpecOpts {oci .WithUIDGID (uid , gid , sgids )}
177- if meta .ReadonlyRootFS {
178- opts = append (opts , containerdoci .WithRootFSReadonly ())
179- }
180-
181- processMode := oci .ProcessSandbox // FIXME(AkihiroSuda)
182- spec , cleanup , err := oci .GenerateSpec (ctx , meta , mounts , id , resolvConf , hostsFile , namespace , w .cgroupParent , processMode , nil , w .apparmorProfile , w .selinux , w .traceSocket , opts ... )
140+ spec , releaseSpec , err := w .createOCISpec (ctx , id , resolvConf , hostsFile , namespace , mounts , meta , details )
183141 if err != nil {
184142 return nil , err
185143 }
186- defer cleanup ()
187- spec .Process .Terminal = meta .Tty
188- if w .rootless {
189- if err := rootlessspecconv .ToRootless (spec ); err != nil {
190- return nil , err
191- }
144+ if releaseSpec != nil {
145+ defer releaseSpec ()
192146 }
193147
194148 container , err := w .client .NewContainer (ctx , id ,
@@ -210,20 +164,12 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
210164 cioOpts = append (cioOpts , cio .WithTerminal )
211165 }
212166
213- rootfs := containerd .WithRootFS ([]mount.Mount {{
214- Source : rootfsPath ,
215- Type : "bind" ,
216- Options : []string {"rbind" },
217- }})
218- if runtime .GOOS == "freebsd" {
219- rootfs = containerd .WithRootFS ([]mount.Mount {{
220- Source : rootfsPath ,
221- Type : "nullfs" ,
222- Options : []string {},
223- }})
167+ taskOpts , err := details .getTaskOpts ()
168+ if err != nil {
169+ return nil , err
224170 }
225171
226- task , err := container .NewTask (ctx , cio .NewCreator (cioOpts ... ), rootfs )
172+ task , err := container .NewTask (ctx , cio .NewCreator (cioOpts ... ), taskOpts )
227173 if err != nil {
228174 return nil , err
229175 }
@@ -259,17 +205,16 @@ func (w *containerdExecutor) Exec(ctx context.Context, id string, process execut
259205 // is in the process of being created and check again every 100ms or until
260206 // context is canceled.
261207
208+ w .mu .Lock ()
209+ details , ok := w .running [id ]
210+ w .mu .Unlock ()
211+
212+ if ! ok {
213+ return errors .Errorf ("container %s not found" , id )
214+ }
262215 var container containerd.Container
263216 var task containerd.Task
264217 for {
265- w .mu .Lock ()
266- done , ok := w .running [id ]
267- w .mu .Unlock ()
268-
269- if ! ok {
270- return errors .Errorf ("container %s not found" , id )
271- }
272-
273218 if container == nil {
274219 container , _ = w .client .LoadContainer (ctx , id )
275220 }
@@ -285,7 +230,7 @@ func (w *containerdExecutor) Exec(ctx context.Context, id string, process execut
285230 select {
286231 case <- ctx .Done ():
287232 return ctx .Err ()
288- case err , ok := <- done :
233+ case err , ok := <- details . done :
289234 if ! ok || err == nil {
290235 return errors .Errorf ("container %s has stopped" , id )
291236 }
@@ -301,23 +246,20 @@ func (w *containerdExecutor) Exec(ctx context.Context, id string, process execut
301246 }
302247
303248 proc := spec .Process
304-
305- // TODO how do we get rootfsPath for oci.GetUser in case user passed in username rather than uid:gid?
306- // For now only support uid:gid
307249 if meta .User != "" {
308- uid , gid , err := oci . ParseUIDGID (meta .User )
250+ userSpec , err := getUserSpec (meta .User , details . rootfsPath )
309251 if err != nil {
310252 return errors .WithStack (err )
311253 }
312- proc .User = specs.User {
313- UID : uid ,
314- GID : gid ,
315- AdditionalGids : []uint32 {},
316- }
254+ proc .User = userSpec
317255 }
318256
319257 proc .Terminal = meta .Tty
320- proc .Args = meta .Args
258+ // setArgs will set the proper command line arguments for this process.
259+ // On Windows, this will set the CommandLine field. On Linux it will set the
260+ // Args field.
261+ setArgs (proc , meta .Args )
262+
321263 if meta .Cwd != "" {
322264 spec .Process .Cwd = meta .Cwd
323265 }
0 commit comments