Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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) |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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, ©WaitGroup); 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, ©WaitGroup); 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, ©WaitGroup) |
| 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, ©WaitGroup); 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)
|