@@ -21,10 +21,10 @@ import (
2121 "github.com/Microsoft/hcsshim/internal/layers"
2222 "github.com/Microsoft/hcsshim/internal/log"
2323 "github.com/Microsoft/hcsshim/internal/queue"
24+ "github.com/Microsoft/hcsshim/internal/resources"
2425 "github.com/Microsoft/hcsshim/internal/winapi"
2526 specs "github.com/opencontainers/runtime-spec/specs-go"
2627 "github.com/pkg/errors"
27- "github.com/sirupsen/logrus"
2828 "golang.org/x/sys/windows"
2929)
3030
@@ -66,7 +66,6 @@ type JobContainer struct {
6666 spec * specs.Spec // OCI spec used to create the container
6767 job * jobobject.JobObject // Object representing the job object the container owns
6868 sandboxMount string // Path to where the sandbox is mounted on the host
69- m sync.Mutex
7069 closedWaitOnce sync.Once
7170 init initProc
7271 startTimestamp time.Time
@@ -89,33 +88,21 @@ func newJobContainer(id string, s *specs.Spec) *JobContainer {
8988}
9089
9190// Create creates a new JobContainer from `s`.
92- func Create (ctx context.Context , id string , s * specs.Spec ) (_ cow.Container , err error ) {
91+ func Create (ctx context.Context , id string , s * specs.Spec ) (_ cow.Container , _ * resources. Resources , err error ) {
9392 log .G (ctx ).WithField ("id" , id ).Debug ("Creating job container" )
9493
9594 if s == nil {
96- return nil , errors .New ("Spec must be supplied" )
95+ return nil , nil , errors .New ("Spec must be supplied" )
9796 }
9897
9998 if id == "" {
10099 g , err := guid .NewV4 ()
101100 if err != nil {
102- return nil , err
101+ return nil , nil , err
103102 }
104103 id = g .String ()
105104 }
106105
107- if err := mountLayers (ctx , s ); err != nil {
108- return nil , errors .Wrap (err , "failed to mount container layers" )
109- }
110-
111- 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}\}(|\\)$`
112- if matched , err := regexp .MatchString (volumeGUIDRegex , s .Root .Path ); ! matched || err != nil {
113- return nil , fmt .Errorf (`invalid container spec - Root.Path '%s' must be a volume GUID path in the format '\\?\Volume{GUID}\'` , s .Root .Path )
114- }
115- if s .Root .Path [len (s .Root .Path )- 1 ] != '\\' {
116- s .Root .Path += `\` // Be nice to clients and make sure well-formed for back-compat
117- }
118-
119106 container := newJobContainer (id , s )
120107
121108 // Create the job object all processes will run in.
@@ -125,52 +112,50 @@ func Create(ctx context.Context, id string, s *specs.Spec) (_ cow.Container, err
125112 }
126113 job , err := jobobject .Create (ctx , options )
127114 if err != nil {
128- return nil , errors .Wrap (err , "failed to create job object" )
115+ return nil , nil , errors .Wrap (err , "failed to create job object" )
129116 }
130117
131118 // Parity with how we handle process isolated containers. We set the same flag which
132119 // behaves the same way for a silo.
133120 if err := job .SetTerminateOnLastHandleClose (); err != nil {
134- return nil , errors .Wrap (err , "failed to set terminate on last handle close on job container" )
121+ return nil , nil , errors .Wrap (err , "failed to set terminate on last handle close on job container" )
135122 }
136123 container .job = job
137124
138- var path string
125+ r := resources . NewContainerResources ( id )
139126 defer func () {
140127 if err != nil {
141128 container .Close ()
142- if path != "" {
143- _ = removeSandboxMountPoint (ctx , path )
144- }
129+ _ = resources .ReleaseResources (ctx , r , nil , true )
145130 }
146131 }()
147132
148- limits , err := specToLimits ( ctx , id , s )
149- if err != nil {
150- return nil , errors .Wrap (err , "failed to convert OCI spec to job object limits " )
133+ sandboxPath := fmt . Sprintf ( sandboxMountFormat , id )
134+ if err := mountLayers ( ctx , s , sandboxPath ); err != nil {
135+ return nil , nil , errors .Wrap (err , "failed to mount container layers " )
151136 }
137+ container .sandboxMount = sandboxPath
152138
153- // Set resource limits on the job object based off of oci spec.
154- if err := job .SetResourceLimits (limits ); err != nil {
155- return nil , errors .Wrap (err , "failed to set resource limits" )
139+ layers := layers .NewImageLayers (nil , "" , s .Windows .LayerFolders , sandboxPath , false )
140+ r .SetLayers (layers )
141+
142+ 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}\}(|\\)$`
143+ if matched , err := regexp .MatchString (volumeGUIDRegex , s .Root .Path ); ! matched || err != nil {
144+ 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 )
156145 }
157146
158- // Setup directory sandbox volume will be mounted
159- sandboxPath := fmt .Sprintf (sandboxMountFormat , id )
160- if _ , err := os .Stat (sandboxPath ); os .IsNotExist (err ) {
161- if err := os .MkdirAll (sandboxPath , 0777 ); err != nil {
162- return nil , errors .Wrap (err , "failed to create mounted folder" )
163- }
147+ limits , err := specToLimits (ctx , id , s )
148+ if err != nil {
149+ return nil , nil , errors .Wrap (err , "failed to convert OCI spec to job object limits" )
164150 }
165- path = sandboxPath
166151
167- if err := mountSandboxVolume (ctx , path , s .Root .Path ); err != nil {
168- return nil , errors .Wrap (err , "failed to bind payload directory on host" )
152+ // Set resource limits on the job object based off of oci spec.
153+ if err := job .SetResourceLimits (limits ); err != nil {
154+ return nil , nil , errors .Wrap (err , "failed to set resource limits" )
169155 }
170156
171- container .sandboxMount = path
172157 go container .waitBackground (ctx )
173- return container , nil
158+ return container , r , nil
174159}
175160
176161// CreateProcess creates a process on the host, starts it, adds it to the containers
@@ -283,29 +268,6 @@ func (c *JobContainer) Modify(ctx context.Context, config interface{}) (err erro
283268 return errors .New ("modify not supported for job containers" )
284269}
285270
286- // Release unmounts all of the container layers. Safe to call multiple times, if no storage
287- // is mounted this call will just return nil.
288- func (c * JobContainer ) Release (ctx context.Context ) error {
289- c .m .Lock ()
290- defer c .m .Unlock ()
291-
292- log .G (ctx ).WithFields (logrus.Fields {
293- "id" : c .id ,
294- "path" : c .sandboxMount ,
295- }).Warn ("removing sandbox volume mount" )
296-
297- if c .sandboxMount != "" {
298- if err := removeSandboxMountPoint (ctx , c .sandboxMount ); err != nil {
299- return errors .Wrap (err , "failed to remove sandbox volume mount path" )
300- }
301- if err := layers .UnmountContainerLayers (ctx , c .spec .Windows .LayerFolders , "" , nil , layers .UnmountOperationAll ); err != nil {
302- return errors .Wrap (err , "failed to unmount container layers" )
303- }
304- c .sandboxMount = ""
305- }
306- return nil
307- }
308-
309271// Start starts the container. There's nothing to "start" for job containers, so this just
310272// sets the start timestamp.
311273func (c * JobContainer ) Start (ctx context.Context ) error {
@@ -484,7 +446,7 @@ func (c *JobContainer) waitBackground(ctx context.Context) {
484446 // them to exit.
485447 <- c .init .proc .waitBlock
486448
487- ctx , cancel := context .WithTimeout (ctx , 10 * time .Second )
449+ ctx , cancel := context .WithTimeout (ctx , 5 * time .Second )
488450 defer cancel ()
489451 if err := c .Shutdown (ctx ); err != nil {
490452 _ = c .Terminate (ctx )
0 commit comments