Browse code

Update containerd to 1.2.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2019/02/12 22:16:54
Showing 32 changed files
... ...
@@ -4,7 +4,7 @@
4 4
 # containerd is also pinned in vendor.conf. When updating the binary
5 5
 # version you may also need to update the vendor version to pick up bug
6 6
 # fixes or new APIs.
7
-CONTAINERD_COMMIT=9754871865f7fe2f4e74d43e2fc7ccd237edcbce # v1.2.2
7
+CONTAINERD_COMMIT=7f5f1176dd9fb3cc8d3ce5de91759ed3dc969fa2 # v1.2.3
8 8
 
9 9
 install_containerd() {
10 10
 	echo "Install containerd version $CONTAINERD_COMMIT"
... ...
@@ -78,7 +78,7 @@ google.golang.org/grpc v1.12.0
78 78
 # the containerd project first, and update both after that is merged.
79 79
 # This commit does not need to match RUNC_COMMIT as it is used for helper
80 80
 # packages but should be newer or equal.
81
-github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
81
+github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
82 82
 github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
83 83
 github.com/opencontainers/image-spec v1.0.1
84 84
 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
... ...
@@ -117,12 +117,12 @@ github.com/googleapis/gax-go v2.0.0
117 117
 google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
118 118
 
119 119
 # containerd
120
-github.com/containerd/containerd 9754871865f7fe2f4e74d43e2fc7ccd237edcbce # v1.2.2
120
+github.com/containerd/containerd 7f5f1176dd9fb3cc8d3ce5de91759ed3dc969fa2 # v1.2.3
121 121
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
122 122
 github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
123 123
 github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
124 124
 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
125
-github.com/containerd/cri 0d5cabd006cb5319dc965046067b8432d9fa5ef8 # release/1.2 branch
125
+github.com/containerd/cri c3cf754321fc38c6af5dfd2552fdde0ad192b31d # release/1.2 branch
126 126
 github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
127 127
 github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
128 128
 github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a
... ...
@@ -100,7 +100,7 @@ const (
100 100
 	// readdir calls to this directory do not follow to lower layers.
101 101
 	whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
102 102
 
103
-	paxSchilyXattr = "SCHILY.xattrs."
103
+	paxSchilyXattr = "SCHILY.xattr."
104 104
 )
105 105
 
106 106
 // Apply applies a tar stream of an OCI style diff tar.
... ...
@@ -295,7 +295,7 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
295 295
 			linkBasename := filepath.Base(hdr.Linkname)
296 296
 			srcHdr = aufsHardlinks[linkBasename]
297 297
 			if srcHdr == nil {
298
-				return 0, fmt.Errorf("Invalid aufs hardlink")
298
+				return 0, fmt.Errorf("invalid aufs hardlink")
299 299
 			}
300 300
 			p, err := fs.RootPath(aufsTempdir, linkBasename)
301 301
 			if err != nil {
... ...
@@ -74,7 +74,7 @@ func tarName(p string) (string, error) {
74 74
 	// in file names, it is mostly safe to replace however we must
75 75
 	// check just in case
76 76
 	if strings.Contains(p, "/") {
77
-		return "", fmt.Errorf("Windows path contains forward slash: %s", p)
77
+		return "", fmt.Errorf("windows path contains forward slash: %s", p)
78 78
 	}
79 79
 
80 80
 	return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
... ...
@@ -130,11 +130,7 @@ func skipFile(hdr *tar.Header) bool {
130 130
 	// specific or Linux-specific, this warning should be changed to an error
131 131
 	// to cater for the situation where someone does manage to upload a Linux
132 132
 	// image but have it tagged as Windows inadvertently.
133
-	if strings.Contains(hdr.Name, ":") {
134
-		return true
135
-	}
136
-
137
-	return false
133
+	return strings.Contains(hdr.Name, ":")
138 134
 }
139 135
 
140 136
 // handleTarTypeBlockCharFifo is an OS-specific helper function used by
... ...
@@ -401,12 +401,22 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
401 401
 	}
402 402
 
403 403
 	var (
404
-		schema1Converter *schema1.Converter
405
-		handler          images.Handler
404
+		handler images.Handler
405
+
406
+		isConvertible bool
407
+		converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error)
406 408
 	)
409
+
407 410
 	if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 {
408
-		schema1Converter = schema1.NewConverter(store, fetcher)
411
+		schema1Converter := schema1.NewConverter(store, fetcher)
412
+
409 413
 		handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...)
414
+
415
+		isConvertible = true
416
+
417
+		converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) {
418
+			return schema1Converter.Convert(ctx)
419
+		}
410 420
 	} else {
411 421
 		// Get all the children for a descriptor
412 422
 		childrenHandler := images.ChildrenHandler(store)
... ...
@@ -419,18 +429,34 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
419 419
 			childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit)
420 420
 		}
421 421
 
422
+		// set isConvertible to true if there is application/octet-stream media type
423
+		convertibleHandler := images.HandlerFunc(
424
+			func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
425
+				if desc.MediaType == docker.LegacyConfigMediaType {
426
+					isConvertible = true
427
+				}
428
+
429
+				return []ocispec.Descriptor{}, nil
430
+			},
431
+		)
432
+
422 433
 		handler = images.Handlers(append(rCtx.BaseHandlers,
423 434
 			remotes.FetchHandler(store, fetcher),
435
+			convertibleHandler,
424 436
 			childrenHandler,
425 437
 		)...)
438
+
439
+		converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
440
+			return docker.ConvertManifest(ctx, store, desc)
441
+		}
426 442
 	}
427 443
 
428 444
 	if err := images.Dispatch(ctx, handler, desc); err != nil {
429 445
 		return images.Image{}, err
430 446
 	}
431
-	if schema1Converter != nil {
432
-		desc, err = schema1Converter.Convert(ctx)
433
-		if err != nil {
447
+
448
+	if isConvertible {
449
+		if desc, err = converterFunc(ctx, desc); err != nil {
434 450
 			return images.Image{}, err
435 451
 		}
436 452
 	}
... ...
@@ -47,7 +47,5 @@ func unlock(ref string) {
47 47
 	locksMu.Lock()
48 48
 	defer locksMu.Unlock()
49 49
 
50
-	if _, ok := locks[ref]; ok {
51
-		delete(locks, ref)
52
-	}
50
+	delete(locks, ref)
53 51
 }
... ...
@@ -37,10 +37,10 @@ func WithProfile(profile string) oci.SpecOpts {
37 37
 		s.Linux.Seccomp = &specs.LinuxSeccomp{}
38 38
 		f, err := ioutil.ReadFile(profile)
39 39
 		if err != nil {
40
-			return fmt.Errorf("Cannot load seccomp profile %q: %v", profile, err)
40
+			return fmt.Errorf("cannot load seccomp profile %q: %v", profile, err)
41 41
 		}
42 42
 		if err := json.Unmarshal(f, s.Linux.Seccomp); err != nil {
43
-			return fmt.Errorf("Decoding seccomp profile failed %q: %v", profile, err)
43
+			return fmt.Errorf("decoding seccomp profile failed %q: %v", profile, err)
44 44
 		}
45 45
 		return nil
46 46
 	}
... ...
@@ -185,7 +185,6 @@ func (s *scanner) scanQuoted(quote rune) {
185 185
 			ch = s.next()
186 186
 		}
187 187
 	}
188
-	return
189 188
 }
190 189
 
191 190
 func (s *scanner) scanEscape(quote rune) rune {
... ...
@@ -99,8 +99,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
99 99
 		})
100 100
 	}
101 101
 
102
-	var handler images.HandlerFunc
103
-	handler = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
102
+	var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
104 103
 		// Only save images at top level
105 104
 		if desc.Digest != index.Digest {
106 105
 			return images.Children(ctx, cs, desc)
... ...
@@ -762,7 +762,7 @@ func (cs *contentStore) garbageCollect(ctx context.Context) (d time.Duration, er
762 762
 	t1 := time.Now()
763 763
 	defer func() {
764 764
 		if err == nil {
765
-			d = time.Now().Sub(t1)
765
+			d = time.Since(t1)
766 766
 		}
767 767
 		cs.l.Unlock()
768 768
 	}()
... ...
@@ -154,7 +154,7 @@ func (m *DB) Init(ctx context.Context) error {
154 154
 				if err := m.migrate(tx); err != nil {
155 155
 					return errors.Wrapf(err, "failed to migrate to %s.%d", m.schema, m.version)
156 156
 				}
157
-				log.G(ctx).WithField("d", time.Now().Sub(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
157
+				log.G(ctx).WithField("d", time.Since(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
158 158
 			}
159 159
 		}
160 160
 
... ...
@@ -306,7 +306,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
306 306
 				m.cleanupSnapshotter(snapshotterName)
307 307
 
308 308
 				sl.Lock()
309
-				stats.SnapshotD[snapshotterName] = time.Now().Sub(st1)
309
+				stats.SnapshotD[snapshotterName] = time.Since(st1)
310 310
 				sl.Unlock()
311 311
 
312 312
 				wg.Done()
... ...
@@ -321,7 +321,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
321 321
 		go func() {
322 322
 			ct1 := time.Now()
323 323
 			m.cleanupContent()
324
-			stats.ContentD = time.Now().Sub(ct1)
324
+			stats.ContentD = time.Since(ct1)
325 325
 			wg.Done()
326 326
 		}()
327 327
 		m.dirtyCS = false
... ...
@@ -329,7 +329,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
329 329
 
330 330
 	m.dirtyL.Unlock()
331 331
 
332
-	stats.MetaD = time.Now().Sub(t1)
332
+	stats.MetaD = time.Since(t1)
333 333
 	m.wlock.Unlock()
334 334
 
335 335
 	wg.Wait()
... ...
@@ -296,10 +296,6 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
296 296
 
297 297
 		bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots, []byte(ss), []byte(name))
298 298
 		if bkt == nil {
299
-			getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots).ForEach(func(k, v []byte) error {
300
-				return nil
301
-			})
302
-
303 299
 			// Node may be created from dead edge
304 300
 			return nil
305 301
 		}
... ...
@@ -628,7 +628,7 @@ func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err
628 628
 			}
629 629
 		}
630 630
 		if err == nil {
631
-			d = time.Now().Sub(t1)
631
+			d = time.Since(t1)
632 632
 		}
633 633
 	}()
634 634
 
... ...
@@ -68,7 +68,7 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
68 68
 		numFields := len(fields)
69 69
 		if numFields < 10 {
70 70
 			// should be at least 10 fields
71
-			return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
71
+			return nil, fmt.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields)
72 72
 		}
73 73
 		p := Info{}
74 74
 		// ignore any numbers parsing errors, as there should not be any
... ...
@@ -76,7 +76,7 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
76 76
 		p.Parent, _ = strconv.Atoi(fields[1])
77 77
 		mm := strings.Split(fields[2], ":")
78 78
 		if len(mm) != 2 {
79
-			return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
79
+			return nil, fmt.Errorf("parsing '%s' failed: unexpected minor:major pair %s", text, mm)
80 80
 		}
81 81
 		p.Major, _ = strconv.Atoi(mm[0])
82 82
 		p.Minor, _ = strconv.Atoi(mm[1])
... ...
@@ -101,11 +101,11 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
101 101
 			}
102 102
 		}
103 103
 		if i == numFields {
104
-			return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text)
104
+			return nil, fmt.Errorf("parsing '%s' failed: missing separator ('-')", text)
105 105
 		}
106 106
 		// There should be 3 fields after the separator...
107 107
 		if i+4 > numFields {
108
-			return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text)
108
+			return nil, fmt.Errorf("parsing '%s' failed: not enough fields after a separator", text)
109 109
 		}
110 110
 		// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
111 111
 		// (like "//serv/My Documents") _may_ end up having a space in the last field
... ...
@@ -42,10 +42,7 @@ var (
42 42
 
43 43
 // IsSkipPlugin returns true if the error is skipping the plugin
44 44
 func IsSkipPlugin(err error) bool {
45
-	if errors.Cause(err) == ErrSkipPlugin {
46
-		return true
47
-	}
48
-	return false
45
+	return errors.Cause(err) == ErrSkipPlugin
49 46
 }
50 47
 
51 48
 // Type is the type of the plugin
... ...
@@ -111,9 +111,11 @@ func (p *process) Start(ctx context.Context) error {
111 111
 		ExecID:      p.id,
112 112
 	})
113 113
 	if err != nil {
114
-		p.io.Cancel()
115
-		p.io.Wait()
116
-		p.io.Close()
114
+		if p.io != nil {
115
+			p.io.Cancel()
116
+			p.io.Wait()
117
+			p.io.Close()
118
+		}
117 119
 		return errdefs.FromGRPC(err)
118 120
 	}
119 121
 	p.pid = r.Pid
... ...
@@ -79,8 +79,8 @@ func init() {
79 79
 		var t octetType
80 80
 		isCtl := c <= 31 || c == 127
81 81
 		isChar := 0 <= c && c <= 127
82
-		isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
83
-		if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
82
+		isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
83
+		if strings.ContainsRune(" \t\r\n", rune(c)) {
84 84
 			t |= isSpace
85 85
 		}
86 86
 		if isChar && !isCtl && !isSeparator {
87 87
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+/*
1
+   Copyright The containerd Authors.
2
+
3
+   Licensed under the Apache License, Version 2.0 (the "License");
4
+   you may not use this file except in compliance with the License.
5
+   You may obtain a copy of the License at
6
+
7
+       http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+   Unless required by applicable law or agreed to in writing, software
10
+   distributed under the License is distributed on an "AS IS" BASIS,
11
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+   See the License for the specific language governing permissions and
13
+   limitations under the License.
14
+*/
15
+
16
+package docker
17
+
18
+import (
19
+	"bytes"
20
+	"context"
21
+	"encoding/json"
22
+	"fmt"
23
+
24
+	"github.com/containerd/containerd/content"
25
+	"github.com/containerd/containerd/images"
26
+	"github.com/containerd/containerd/log"
27
+	"github.com/containerd/containerd/remotes"
28
+	digest "github.com/opencontainers/go-digest"
29
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
30
+	"github.com/pkg/errors"
31
+)
32
+
33
+// LegacyConfigMediaType should be replaced by OCI image spec.
34
+//
35
+// More detail: docker/distribution#1622
36
+const LegacyConfigMediaType = "application/octet-stream"
37
+
38
+// ConvertManifest changes application/octet-stream to schema2 config media type if need.
39
+//
40
+// NOTE:
41
+// 1. original manifest will be deleted by next gc round.
42
+// 2. don't cover manifest list.
43
+func ConvertManifest(ctx context.Context, store content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
44
+	if !(desc.MediaType == images.MediaTypeDockerSchema2Manifest ||
45
+		desc.MediaType == ocispec.MediaTypeImageManifest) {
46
+
47
+		log.G(ctx).Warnf("do nothing for media type: %s", desc.MediaType)
48
+		return desc, nil
49
+	}
50
+
51
+	// read manifest data
52
+	mb, err := content.ReadBlob(ctx, store, desc)
53
+	if err != nil {
54
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to read index data")
55
+	}
56
+
57
+	var manifest ocispec.Manifest
58
+	if err := json.Unmarshal(mb, &manifest); err != nil {
59
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to unmarshal data into manifest")
60
+	}
61
+
62
+	// check config media type
63
+	if manifest.Config.MediaType != LegacyConfigMediaType {
64
+		return desc, nil
65
+	}
66
+
67
+	manifest.Config.MediaType = images.MediaTypeDockerSchema2Config
68
+	data, err := json.MarshalIndent(manifest, "", "   ")
69
+	if err != nil {
70
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal manifest")
71
+	}
72
+
73
+	// update manifest with gc labels
74
+	desc.Digest = digest.Canonical.FromBytes(data)
75
+	desc.Size = int64(len(data))
76
+
77
+	labels := map[string]string{}
78
+	for i, c := range append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...) {
79
+		labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = c.Digest.String()
80
+	}
81
+
82
+	ref := remotes.MakeRefKey(ctx, desc)
83
+	if err := content.WriteBlob(ctx, store, ref, bytes.NewReader(data), desc, content.WithLabels(labels)); err != nil {
84
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to update content")
85
+	}
86
+	return desc, nil
87
+}
... ...
@@ -69,4 +69,8 @@ type PlatformRuntime interface {
69 69
 	// Tasks returns all the current tasks for the runtime.
70 70
 	// Any container runs at most one task at a time.
71 71
 	Tasks(context.Context, bool) ([]Task, error)
72
+	// Add adds a task into runtime.
73
+	Add(context.Context, Task) error
74
+	// Delete remove a task.
75
+	Delete(context.Context, string)
72 76
 }
... ...
@@ -69,7 +69,3 @@ func (s *deletedState) SetExited(status int) {
69 69
 func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
70 70
 	return nil, errors.Errorf("cannot exec in a deleted state")
71 71
 }
72
-
73
-func (s *deletedState) Pid() int {
74
-	return -1
75
-}
... ...
@@ -49,7 +49,7 @@ type execProcess struct {
49 49
 	io      runc.IO
50 50
 	status  int
51 51
 	exited  time.Time
52
-	pid     int
52
+	pid     *safePid
53 53
 	closers []io.Closer
54 54
 	stdin   io.Closer
55 55
 	stdio   proc.Stdio
... ...
@@ -69,11 +69,7 @@ func (e *execProcess) ID() string {
69 69
 }
70 70
 
71 71
 func (e *execProcess) Pid() int {
72
-	return e.execState.Pid()
73
-}
74
-
75
-func (e *execProcess) pidv() int {
76
-	return e.pid
72
+	return e.pid.get()
77 73
 }
78 74
 
79 75
 func (e *execProcess) ExitStatus() int {
... ...
@@ -145,7 +141,7 @@ func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
145 145
 }
146 146
 
147 147
 func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
148
-	pid := e.pid
148
+	pid := e.pid.get()
149 149
 	if pid != 0 {
150 150
 		if err := unix.Kill(pid, syscall.Signal(sig)); err != nil {
151 151
 			return errors.Wrapf(checkKillError(err), "exec kill error")
... ...
@@ -170,6 +166,12 @@ func (e *execProcess) Start(ctx context.Context) error {
170 170
 }
171 171
 
172 172
 func (e *execProcess) start(ctx context.Context) (err error) {
173
+	// The reaper may receive exit signal right after
174
+	// the container is started, before the e.pid is updated.
175
+	// In that case, we want to block the signal handler to
176
+	// access e.pid until it is updated.
177
+	e.pid.Lock()
178
+	defer e.pid.Unlock()
173 179
 	var (
174 180
 		socket  *runc.Socket
175 181
 		pidfile = filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id))
... ...
@@ -201,7 +203,7 @@ func (e *execProcess) start(ctx context.Context) (err error) {
201 201
 		return e.parent.runtimeError(err, "OCI runtime exec failed")
202 202
 	}
203 203
 	if e.stdio.Stdin != "" {
204
-		sc, err := fifo.OpenFifo(ctx, e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
204
+		sc, err := fifo.OpenFifo(context.Background(), e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
205 205
 		if err != nil {
206 206
 			return errors.Wrapf(err, "failed to open stdin fifo %s", e.stdio.Stdin)
207 207
 		}
... ...
@@ -210,29 +212,26 @@ func (e *execProcess) start(ctx context.Context) (err error) {
210 210
 	}
211 211
 	var copyWaitGroup sync.WaitGroup
212 212
 	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
213
+	defer cancel()
213 214
 	if socket != nil {
214 215
 		console, err := socket.ReceiveMaster()
215 216
 		if err != nil {
216
-			cancel()
217 217
 			return errors.Wrap(err, "failed to retrieve console master")
218 218
 		}
219 219
 		if e.console, err = e.parent.Platform.CopyConsole(ctx, console, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, &copyWaitGroup); err != nil {
220
-			cancel()
221 220
 			return errors.Wrap(err, "failed to start console copy")
222 221
 		}
223 222
 	} else if !e.stdio.IsNull() {
224 223
 		if err := copyPipes(ctx, e.io, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, &copyWaitGroup); err != nil {
225
-			cancel()
226 224
 			return errors.Wrap(err, "failed to start io pipe copy")
227 225
 		}
228 226
 	}
229 227
 	copyWaitGroup.Wait()
230 228
 	pid, err := runc.ReadPidFile(opts.PidFile)
231 229
 	if err != nil {
232
-		cancel()
233 230
 		return errors.Wrap(err, "failed to retrieve OCI runtime exec pid")
234 231
 	}
235
-	e.pid = pid
232
+	e.pid.pid = pid
236 233
 	return nil
237 234
 }
238 235
 
... ...
@@ -250,11 +249,11 @@ func (e *execProcess) Status(ctx context.Context) (string, error) {
250 250
 	e.mu.Lock()
251 251
 	defer e.mu.Unlock()
252 252
 	// if we don't have a pid then the exec process has just been created
253
-	if e.pid == 0 {
253
+	if e.pid.get() == 0 {
254 254
 		return "created", nil
255 255
 	}
256 256
 	// if we have a pid and it can be signaled, the process is running
257
-	if err := unix.Kill(e.pid, 0); err == nil {
257
+	if err := unix.Kill(e.pid.get(), 0); err == nil {
258 258
 		return "running", nil
259 259
 	}
260 260
 	// else if we have a pid but it can nolonger be signaled, it has stopped
... ...
@@ -31,7 +31,6 @@ type execState interface {
31 31
 	Delete(context.Context) error
32 32
 	Kill(context.Context, uint32, bool) error
33 33
 	SetExited(int)
34
-	Pid() int
35 34
 }
36 35
 
37 36
 type execCreatedState struct {
... ...
@@ -83,12 +82,6 @@ func (s *execCreatedState) SetExited(status int) {
83 83
 	}
84 84
 }
85 85
 
86
-func (s *execCreatedState) Pid() int {
87
-	s.p.mu.Lock()
88
-	defer s.p.mu.Unlock()
89
-	return s.p.pidv()
90
-}
91
-
92 86
 type execRunningState struct {
93 87
 	p *execProcess
94 88
 }
... ...
@@ -127,12 +120,6 @@ func (s *execRunningState) SetExited(status int) {
127 127
 	}
128 128
 }
129 129
 
130
-func (s *execRunningState) Pid() int {
131
-	s.p.mu.Lock()
132
-	defer s.p.mu.Unlock()
133
-	return s.p.pidv()
134
-}
135
-
136 130
 type execStoppedState struct {
137 131
 	p *execProcess
138 132
 }
... ...
@@ -170,7 +157,3 @@ func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error
170 170
 func (s *execStoppedState) SetExited(status int) {
171 171
 	// no op
172 172
 }
173
-
174
-func (s *execStoppedState) Pid() int {
175
-	return s.p.pidv()
176
-}
... ...
@@ -160,7 +160,7 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
160 160
 		return p.runtimeError(err, "OCI runtime create failed")
161 161
 	}
162 162
 	if r.Stdin != "" {
163
-		sc, err := fifo.OpenFifo(ctx, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
163
+		sc, err := fifo.OpenFifo(context.Background(), r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
164 164
 		if err != nil {
165 165
 			return errors.Wrapf(err, "failed to open stdin fifo %s", r.Stdin)
166 166
 		}
... ...
@@ -169,21 +169,19 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
169 169
 	}
170 170
 	var copyWaitGroup sync.WaitGroup
171 171
 	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
172
+	defer cancel()
172 173
 	if socket != nil {
173 174
 		console, err := socket.ReceiveMaster()
174 175
 		if err != nil {
175
-			cancel()
176 176
 			return errors.Wrap(err, "failed to retrieve console master")
177 177
 		}
178 178
 		console, err = p.Platform.CopyConsole(ctx, console, r.Stdin, r.Stdout, r.Stderr, &p.wg, &copyWaitGroup)
179 179
 		if err != nil {
180
-			cancel()
181 180
 			return errors.Wrap(err, "failed to start console copy")
182 181
 		}
183 182
 		p.console = console
184 183
 	} else if !hasNoIO(r) {
185 184
 		if err := copyPipes(ctx, p.io, r.Stdin, r.Stdout, r.Stderr, &p.wg, &copyWaitGroup); err != nil {
186
-			cancel()
187 185
 			return errors.Wrap(err, "failed to start io pipe copy")
188 186
 		}
189 187
 	}
... ...
@@ -191,7 +189,6 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
191 191
 	copyWaitGroup.Wait()
192 192
 	pid, err := runc.ReadPidFile(pidFile)
193 193
 	if err != nil {
194
-		cancel()
195 194
 		return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
196 195
 	}
197 196
 	p.pid = pid
... ...
@@ -409,6 +406,7 @@ func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Proce
409 409
 			Terminal: r.Terminal,
410 410
 		},
411 411
 		waitBlock: make(chan struct{}),
412
+		pid:       &safePid{},
412 413
 	}
413 414
 	e.execState = &execCreatedState{p: e}
414 415
 	return e, nil
... ...
@@ -172,7 +172,7 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
172 172
 		return p.runtimeError(err, "OCI runtime restore failed")
173 173
 	}
174 174
 	if sio.Stdin != "" {
175
-		sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
175
+		sc, err := fifo.OpenFifo(context.Background(), sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
176 176
 		if err != nil {
177 177
 			return errors.Wrapf(err, "failed to open stdin fifo %s", sio.Stdin)
178 178
 		}
... ...
@@ -111,7 +111,7 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
111 111
 	if stdin == "" {
112 112
 		return nil
113 113
 	}
114
-	f, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
114
+	f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
115 115
 	if err != nil {
116 116
 		return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err)
117 117
 	}
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"io"
24 24
 	"os"
25 25
 	"strings"
26
+	"sync"
26 27
 	"time"
27 28
 
28 29
 	"github.com/containerd/containerd/errdefs"
... ...
@@ -31,6 +32,18 @@ import (
31 31
 	"golang.org/x/sys/unix"
32 32
 )
33 33
 
34
+// safePid is a thread safe wrapper for pid.
35
+type safePid struct {
36
+	sync.Mutex
37
+	pid int
38
+}
39
+
40
+func (s *safePid) get() int {
41
+	s.Lock()
42
+	defer s.Unlock()
43
+	return s.pid
44
+}
45
+
34 46
 // TODO(mlaventure): move to runc package?
35 47
 func getLastRuntimeError(r *runc.Runc) (string, error) {
36 48
 	if r.Log == "" {
... ...
@@ -303,6 +303,16 @@ func (r *Runtime) Get(ctx context.Context, id string) (runtime.Task, error) {
303 303
 	return r.tasks.Get(ctx, id)
304 304
 }
305 305
 
306
+// Add a runtime task
307
+func (r *Runtime) Add(ctx context.Context, task runtime.Task) error {
308
+	return r.tasks.Add(ctx, task)
309
+}
310
+
311
+// Delete a runtime task
312
+func (r *Runtime) Delete(ctx context.Context, id string) {
313
+	r.tasks.Delete(ctx, id)
314
+}
315
+
306 316
 func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
307 317
 	dir, err := ioutil.ReadDir(filepath.Join(r.state, ns))
308 318
 	if err != nil {
... ...
@@ -185,8 +185,10 @@ func (t *task) Start(ctx context.Context) error {
185 185
 		ContainerID: t.id,
186 186
 	})
187 187
 	if err != nil {
188
-		t.io.Cancel()
189
-		t.io.Close()
188
+		if t.io != nil {
189
+			t.io.Cancel()
190
+			t.io.Close()
191
+		}
190 192
 		return errdefs.FromGRPC(err)
191 193
 	}
192 194
 	t.pid = r.Pid
... ...
@@ -20,7 +20,7 @@ github.com/gogo/protobuf v1.0.0
20 20
 github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
21 21
 github.com/golang/protobuf v1.1.0
22 22
 github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
23
-github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
23
+github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
24 24
 github.com/sirupsen/logrus v1.0.0
25 25
 github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
26 26
 golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
... ...
@@ -43,7 +43,7 @@ github.com/google/go-cmp v0.1.0
43 43
 go.etcd.io/bbolt v1.3.1-etcd.8
44 44
 
45 45
 # cri dependencies
46
-github.com/containerd/cri 0d5cabd006cb5319dc965046067b8432d9fa5ef8 # release/1.2 branch
46
+github.com/containerd/cri c3cf754321fc38c6af5dfd2552fdde0ad192b31d # release/1.2 branch
47 47
 github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
48 48
 github.com/blang/semver v3.1.0
49 49
 github.com/containernetworking/cni v0.6.0
... ...
@@ -22,7 +22,7 @@ import "strings"
22 22
 // Comparison is case insensitive.
23 23
 func InStringSlice(ss []string, str string) bool {
24 24
 	for _, s := range ss {
25
-		if strings.ToLower(s) == strings.ToLower(str) {
25
+		if strings.EqualFold(s, str) {
26 26
 			return true
27 27
 		}
28 28
 	}
... ...
@@ -34,7 +34,7 @@ func InStringSlice(ss []string, str string) bool {
34 34
 func SubtractStringSlice(ss []string, str string) []string {
35 35
 	var res []string
36 36
 	for _, s := range ss {
37
-		if strings.ToLower(s) == strings.ToLower(str) {
37
+		if strings.EqualFold(s, str) {
38 38
 			continue
39 39
 		}
40 40
 		res = append(res, s)
... ...
@@ -3,7 +3,7 @@ github.com/blang/semver v3.1.0
3 3
 github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
4 4
 github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
5 5
 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
6
-github.com/containerd/containerd 4b284fa3ab61832b022ba428055f793a75ffc251
6
+github.com/containerd/containerd 0137339c8c1d55de5545ffdd723199dfba27cb24
7 7
 github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
8 8
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
9 9
 github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
... ...
@@ -39,7 +39,7 @@ github.com/modern-go/concurrent 1.0.3
39 39
 github.com/modern-go/reflect2 1.0.1
40 40
 github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
41 41
 github.com/opencontainers/image-spec v1.0.1
42
-github.com/opencontainers/runc v1.0.0-rc6
42
+github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
43 43
 github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353
44 44
 github.com/opencontainers/runtime-tools v0.6.0
45 45
 github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
... ...
@@ -463,7 +463,7 @@ func WriteCgroupProc(dir string, pid int) error {
463 463
 		return fmt.Errorf("no such directory for %s", CgroupProcesses)
464 464
 	}
465 465
 
466
-	// Dont attach any pid to the cgroup if -1 is specified as a pid
466
+	// Don't attach any pid to the cgroup if -1 is specified as a pid
467 467
 	if pid != -1 {
468 468
 		if err := ioutil.WriteFile(filepath.Join(dir, CgroupProcesses), []byte(strconv.Itoa(pid)), 0700); err != nil {
469 469
 			return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err)