Browse Source

Merge pull request #39713 from thaJeztah/containerd_1.3

bump containerd and dependencies to v1.3.0
Tibor Vass 5 years ago
parent
commit
b3be2802d4
100 changed files with 5706 additions and 1293 deletions
  1. 2 2
      builder/builder-next/adapters/localinlinecache/inlinecache.go
  2. 1 1
      builder/builder-next/controller.go
  3. 9 4
      builder/builder-next/worker/worker.go
  4. 7 2
      daemon/daemon.go
  5. 1 1
      hack/dockerfile/install/containerd.installer
  6. 7 7
      vendor.conf
  7. 1 0
      vendor/github.com/containerd/cgroups/blkio.go
  8. 3 0
      vendor/github.com/containerd/cgroups/cgroup.go
  9. 4 0
      vendor/github.com/containerd/cgroups/memory.go
  10. 531 123
      vendor/github.com/containerd/cgroups/metrics.pb.go
  11. 13 0
      vendor/github.com/containerd/cgroups/metrics.proto
  12. 1 1
      vendor/github.com/containerd/cgroups/utils.go
  13. 1 1
      vendor/github.com/containerd/containerd/README.md
  14. 227 39
      vendor/github.com/containerd/containerd/api/services/diff/v1/diff.pb.go
  15. 3 0
      vendor/github.com/containerd/containerd/api/services/diff/v1/diff.proto
  16. 252 32
      vendor/github.com/containerd/containerd/api/services/introspection/v1/introspection.pb.go
  17. 7 0
      vendor/github.com/containerd/containerd/api/services/introspection/v1/introspection.proto
  18. 1309 96
      vendor/github.com/containerd/containerd/api/services/leases/v1/leases.pb.go
  19. 38 0
      vendor/github.com/containerd/containerd/api/services/leases/v1/leases.proto
  20. 1 1
      vendor/github.com/containerd/containerd/archive/compression/compression.go
  21. 150 107
      vendor/github.com/containerd/containerd/archive/tar.go
  22. 37 1
      vendor/github.com/containerd/containerd/archive/tar_opts.go
  23. 59 0
      vendor/github.com/containerd/containerd/archive/tar_opts_linux.go
  24. 1 17
      vendor/github.com/containerd/containerd/archive/tar_opts_windows.go
  25. 67 10
      vendor/github.com/containerd/containerd/archive/tar_unix.go
  26. 15 16
      vendor/github.com/containerd/containerd/archive/tar_windows.go
  27. 1 1
      vendor/github.com/containerd/containerd/archive/time_unix.go
  28. 22 7
      vendor/github.com/containerd/containerd/cio/io.go
  29. 12 10
      vendor/github.com/containerd/containerd/cio/io_unix.go
  30. 124 33
      vendor/github.com/containerd/containerd/client.go
  31. 17 9
      vendor/github.com/containerd/containerd/client_opts.go
  32. 32 9
      vendor/github.com/containerd/containerd/container.go
  33. 61 27
      vendor/github.com/containerd/containerd/container_opts.go
  34. 11 7
      vendor/github.com/containerd/containerd/container_opts_unix.go
  35. 1 2
      vendor/github.com/containerd/containerd/container_restore_opts.go
  36. 1 1
      vendor/github.com/containerd/containerd/containers/containers.go
  37. 30 1
      vendor/github.com/containerd/containerd/content/helpers.go
  38. 14 2
      vendor/github.com/containerd/containerd/content/local/store.go
  39. 1 1
      vendor/github.com/containerd/containerd/contrib/nvidia/nvidia.go
  40. 0 2
      vendor/github.com/containerd/containerd/contrib/seccomp/seccomp.go
  41. 5 3
      vendor/github.com/containerd/containerd/contrib/seccomp/seccomp_default.go
  42. 9 2
      vendor/github.com/containerd/containerd/contrib/seccomp/seccomp_default_unsupported.go
  43. 2 2
      vendor/github.com/containerd/containerd/defaults/defaults.go
  44. 2 0
      vendor/github.com/containerd/containerd/defaults/defaults_unix.go
  45. 2 0
      vendor/github.com/containerd/containerd/defaults/defaults_windows.go
  46. 10 3
      vendor/github.com/containerd/containerd/diff.go
  47. 19 1
      vendor/github.com/containerd/containerd/diff/diff.go
  48. 187 0
      vendor/github.com/containerd/containerd/diff/stream.go
  49. 146 0
      vendor/github.com/containerd/containerd/diff/stream_unix.go
  50. 165 0
      vendor/github.com/containerd/containerd/diff/stream_windows.go
  51. 16 1
      vendor/github.com/containerd/containerd/errdefs/errors.go
  52. 9 0
      vendor/github.com/containerd/containerd/errdefs/grpc.go
  53. 1 1
      vendor/github.com/containerd/containerd/events/exchange/exchange.go
  54. 6 20
      vendor/github.com/containerd/containerd/export.go
  55. 7 0
      vendor/github.com/containerd/containerd/gc/gc.go
  56. 174 9
      vendor/github.com/containerd/containerd/image.go
  57. 6 7
      vendor/github.com/containerd/containerd/images/annotations.go
  58. 468 0
      vendor/github.com/containerd/containerd/images/archive/exporter.go
  59. 133 21
      vendor/github.com/containerd/containerd/images/archive/importer.go
  60. 28 2
      vendor/github.com/containerd/containerd/images/archive/reference.go
  61. 4 3
      vendor/github.com/containerd/containerd/images/handlers.go
  62. 19 41
      vendor/github.com/containerd/containerd/images/image.go
  63. 84 0
      vendor/github.com/containerd/containerd/images/mediatypes.go
  64. 0 241
      vendor/github.com/containerd/containerd/images/oci/exporter.go
  65. 38 13
      vendor/github.com/containerd/containerd/import.go
  66. 1 2
      vendor/github.com/containerd/containerd/install.go
  67. 10 0
      vendor/github.com/containerd/containerd/leases/lease.go
  68. 40 0
      vendor/github.com/containerd/containerd/leases/proxy/manager.go
  69. 1 1
      vendor/github.com/containerd/containerd/log/context.go
  70. 145 114
      vendor/github.com/containerd/containerd/metadata/containers.go
  71. 5 3
      vendor/github.com/containerd/containerd/metadata/content.go
  72. 18 15
      vendor/github.com/containerd/containerd/metadata/db.go
  73. 33 6
      vendor/github.com/containerd/containerd/metadata/gc.go
  74. 8 10
      vendor/github.com/containerd/containerd/metadata/images.go
  75. 242 56
      vendor/github.com/containerd/containerd/metadata/leases.go
  76. 9 1
      vendor/github.com/containerd/containerd/metadata/namespaces.go
  77. 38 5
      vendor/github.com/containerd/containerd/metadata/snapshot.go
  78. 12 4
      vendor/github.com/containerd/containerd/namespaces.go
  79. 6 8
      vendor/github.com/containerd/containerd/namespaces/context.go
  80. 10 1
      vendor/github.com/containerd/containerd/namespaces/store.go
  81. 51 0
      vendor/github.com/containerd/containerd/namespaces/ttrpc.go
  82. 1 2
      vendor/github.com/containerd/containerd/oci/spec.go
  83. 112 4
      vendor/github.com/containerd/containerd/oci/spec_opts.go
  84. 64 0
      vendor/github.com/containerd/containerd/oci/spec_opts_linux.go
  85. 63 0
      vendor/github.com/containerd/containerd/oci/spec_opts_unix.go
  86. 5 0
      vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
  87. 13 1
      vendor/github.com/containerd/containerd/pkg/dialer/dialer.go
  88. 2 3
      vendor/github.com/containerd/containerd/pkg/process/deleted_state.go
  89. 18 8
      vendor/github.com/containerd/containerd/pkg/process/exec.go
  90. 1 1
      vendor/github.com/containerd/containerd/pkg/process/exec_state.go
  91. 18 22
      vendor/github.com/containerd/containerd/pkg/process/init.go
  92. 11 31
      vendor/github.com/containerd/containerd/pkg/process/init_state.go
  93. 16 12
      vendor/github.com/containerd/containerd/pkg/process/io.go
  94. 3 25
      vendor/github.com/containerd/containerd/pkg/process/process.go
  95. 1 1
      vendor/github.com/containerd/containerd/pkg/process/types.go
  96. 53 4
      vendor/github.com/containerd/containerd/pkg/process/utils.go
  97. 33 0
      vendor/github.com/containerd/containerd/pkg/stdio/platform.go
  98. 11 9
      vendor/github.com/containerd/containerd/pkg/stdio/stdio.go
  99. 37 0
      vendor/github.com/containerd/containerd/platforms/compare.go
  100. 1 1
      vendor/github.com/containerd/containerd/platforms/cpuinfo.go

+ 2 - 2
builder/builder-next/adapters/localinlinecache/inlinecache.go

@@ -23,9 +23,9 @@ import (
 )
 )
 
 
 // ResolveCacheImporterFunc returns a resolver function for local inline cache
 // ResolveCacheImporterFunc returns a resolver function for local inline cache
-func ResolveCacheImporterFunc(sm *session.Manager, resolverOpt resolver.ResolveOptionsFunc, rs reference.Store, is imagestore.Store) remotecache.ResolveCacheImporterFunc {
+func ResolveCacheImporterFunc(sm *session.Manager, resolverOpt resolver.ResolveOptionsFunc, cs content.Store, rs reference.Store, is imagestore.Store) remotecache.ResolveCacheImporterFunc {
 
 
-	upstream := registryremotecache.ResolveCacheImporterFunc(sm, resolverOpt)
+	upstream := registryremotecache.ResolveCacheImporterFunc(sm, cs, resolverOpt)
 
 
 	return func(ctx context.Context, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) {
 	return func(ctx context.Context, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) {
 		if dt, err := tryImportLocal(rs, is, attrs["ref"]); err == nil {
 		if dt, err := tryImportLocal(rs, is, attrs["ref"]); err == nil {

+ 1 - 1
builder/builder-next/controller.go

@@ -189,7 +189,7 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
 		Frontends:        frontends,
 		Frontends:        frontends,
 		CacheKeyStorage:  cacheStorage,
 		CacheKeyStorage:  cacheStorage,
 		ResolveCacheImporterFuncs: map[string]remotecache.ResolveCacheImporterFunc{
 		ResolveCacheImporterFuncs: map[string]remotecache.ResolveCacheImporterFunc{
-			"registry": localinlinecache.ResolveCacheImporterFunc(opt.SessionManager, opt.ResolverOpt, dist.ReferenceStore, dist.ImageStore),
+			"registry": localinlinecache.ResolveCacheImporterFunc(opt.SessionManager, opt.ResolverOpt, store, dist.ReferenceStore, dist.ImageStore),
 			"local":    localremotecache.ResolveCacheImporterFunc(opt.SessionManager),
 			"local":    localremotecache.ResolveCacheImporterFunc(opt.SessionManager),
 		},
 		},
 		ResolveCacheExporterFuncs: map[string]remotecache.ResolveCacheExporterFunc{
 		ResolveCacheExporterFuncs: map[string]remotecache.ResolveCacheExporterFunc{

+ 9 - 4
builder/builder-next/worker/worker.go

@@ -151,6 +151,11 @@ func (w *Worker) GCPolicy() []client.PruneInfo {
 	return w.Opt.GCPolicy
 	return w.Opt.GCPolicy
 }
 }
 
 
+// ContentStore returns content store
+func (w *Worker) ContentStore() content.Store {
+	return w.Opt.ContentStore
+}
+
 // LoadRef loads a reference by ID
 // LoadRef loads a reference by ID
 func (w *Worker) LoadRef(id string, hidden bool) (cache.ImmutableRef, error) {
 func (w *Worker) LoadRef(id string, hidden bool) (cache.ImmutableRef, error) {
 	var opts []cache.RefOption
 	var opts []cache.RefOption
@@ -322,7 +327,7 @@ func (w *Worker) FromRemote(ctx context.Context, remote *solver.Remote) (cache.I
 
 
 	defer func() {
 	defer func() {
 		for _, l := range rootfs {
 		for _, l := range rootfs {
-			w.ContentStore.Delete(context.TODO(), l.Blob.Digest)
+			w.ContentStore().Delete(context.TODO(), l.Blob.Digest)
 		}
 		}
 	}()
 	}()
 
 
@@ -391,12 +396,12 @@ func (ld *layerDescriptor) DiffID() (layer.DiffID, error) {
 
 
 func (ld *layerDescriptor) Download(ctx context.Context, progressOutput pkgprogress.Output) (io.ReadCloser, int64, error) {
 func (ld *layerDescriptor) Download(ctx context.Context, progressOutput pkgprogress.Output) (io.ReadCloser, int64, error) {
 	done := oneOffProgress(ld.pctx, fmt.Sprintf("pulling %s", ld.desc.Digest))
 	done := oneOffProgress(ld.pctx, fmt.Sprintf("pulling %s", ld.desc.Digest))
-	if err := contentutil.Copy(ctx, ld.w.ContentStore, ld.provider, ld.desc); err != nil {
+	if err := contentutil.Copy(ctx, ld.w.ContentStore(), ld.provider, ld.desc); err != nil {
 		return nil, 0, done(err)
 		return nil, 0, done(err)
 	}
 	}
 	_ = done(nil)
 	_ = done(nil)
 
 
-	ra, err := ld.w.ContentStore.ReaderAt(ctx, ld.desc)
+	ra, err := ld.w.ContentStore().ReaderAt(ctx, ld.desc)
 	if err != nil {
 	if err != nil {
 		return nil, 0, err
 		return nil, 0, err
 	}
 	}
@@ -405,7 +410,7 @@ func (ld *layerDescriptor) Download(ctx context.Context, progressOutput pkgprogr
 }
 }
 
 
 func (ld *layerDescriptor) Close() {
 func (ld *layerDescriptor) Close() {
-	// ld.is.ContentStore.Delete(context.TODO(), ld.desc.Digest)
+	// ld.is.ContentStore().Delete(context.TODO(), ld.desc.Digest)
 }
 }
 
 
 func (ld *layerDescriptor) Registered(diffID layer.DiffID) {
 func (ld *layerDescriptor) Registered(diffID layer.DiffID) {

+ 7 - 2
daemon/daemon.go

@@ -173,8 +173,9 @@ func (daemon *Daemon) NewResolveOptionsFunc() resolver.ResolveOptionsFunc {
 			if uri, err := url.Parse(v); err == nil {
 			if uri, err := url.Parse(v); err == nil {
 				v = uri.Host
 				v = uri.Host
 			}
 			}
+			plainHTTP := true
 			m[v] = resolver.RegistryConf{
 			m[v] = resolver.RegistryConf{
-				PlainHTTP: true,
+				PlainHTTP: &plainHTTP,
 			}
 			}
 		}
 		}
 		def := docker.ResolverOptions{
 		def := docker.ResolverOptions{
@@ -193,12 +194,16 @@ func (daemon *Daemon) NewResolveOptionsFunc() resolver.ResolveOptionsFunc {
 		}
 		}
 
 
 		if len(c.Mirrors) > 0 {
 		if len(c.Mirrors) > 0 {
+			// TODO ResolverOptions.Host is deprecated; ResolverOptions.Hosts should be used
 			def.Host = func(string) (string, error) {
 			def.Host = func(string) (string, error) {
 				return c.Mirrors[rand.Intn(len(c.Mirrors))], nil
 				return c.Mirrors[rand.Intn(len(c.Mirrors))], nil
 			}
 			}
 		}
 		}
 
 
-		def.PlainHTTP = c.PlainHTTP
+		// TODO ResolverOptions.PlainHTTP is deprecated; ResolverOptions.Hosts should be used
+		if c.PlainHTTP != nil {
+			def.PlainHTTP = *c.PlainHTTP
+		}
 
 
 		return def
 		return def
 	}
 	}

+ 1 - 1
hack/dockerfile/install/containerd.installer

@@ -4,7 +4,7 @@
 # containerd is also pinned in vendor.conf. When updating the binary
 # containerd is also pinned in vendor.conf. When updating the binary
 # version you may also need to update the vendor version to pick up bug
 # version you may also need to update the vendor version to pick up bug
 # fixes or new APIs.
 # fixes or new APIs.
-CONTAINERD_COMMIT=b34a5c8af56e510852c35414db4c1f4fa6172339 # v1.2.10
+CONTAINERD_COMMIT=36cf5b690dcc00ff0f34ff7799209050c3d0c59a # v1.3.0
 
 
 install_containerd() {
 install_containerd() {
 	echo "Install containerd version $CONTAINERD_COMMIT"
 	echo "Install containerd version $CONTAINERD_COMMIT"

+ 7 - 7
vendor.conf

@@ -26,7 +26,7 @@ github.com/imdario/mergo                            1afb36080aec31e0d1528973ebe6
 golang.org/x/sync                                   e225da77a7e68af35c70ccbf71af2b83e6acac3c
 golang.org/x/sync                                   e225da77a7e68af35c70ccbf71af2b83e6acac3c
 
 
 # buildkit
 # buildkit
-github.com/moby/buildkit                            588c73e1e4f0f3d7d3738abaaa7cf8026064b33e
+github.com/moby/buildkit                            f7042823e340d38d1746aa675b83d1aca431cee3
 github.com/tonistiigi/fsutil                        3bbb99cdbd76619ab717299830c60f6f2a533a6b
 github.com/tonistiigi/fsutil                        3bbb99cdbd76619ab717299830c60f6f2a533a6b
 github.com/grpc-ecosystem/grpc-opentracing          8e809c8a86450a29b90dcc9efbf062d0fe6d9746
 github.com/grpc-ecosystem/grpc-opentracing          8e809c8a86450a29b90dcc9efbf062d0fe6d9746
 github.com/opentracing/opentracing-go               1361b9cd60be79c4c3a7fa9841b3c132e40066a7
 github.com/opentracing/opentracing-go               1361b9cd60be79c4c3a7fa9841b3c132e40066a7
@@ -117,12 +117,12 @@ github.com/googleapis/gax-go                        317e0006254c44a0ac427cc52a0e
 google.golang.org/genproto                          694d95ba50e67b2e363f3483057db5d4910c18f9
 google.golang.org/genproto                          694d95ba50e67b2e363f3483057db5d4910c18f9
 
 
 # containerd
 # containerd
-github.com/containerd/containerd                    7c1e88399ec0b0b077121d9d5ad97e647b11c870
-github.com/containerd/fifo                          a9fb20d87448d386e6d50b1f2e1fa70dcf0de43c
-github.com/containerd/continuity                    aaeac12a7ffcd198ae25440a9dff125c2e2703a7
-github.com/containerd/cgroups                       4994991857f9b0ae8dc439551e8bebdbb4bf66c1
+github.com/containerd/containerd                    36cf5b690dcc00ff0f34ff7799209050c3d0c59a # v1.3.0
+github.com/containerd/fifo                          bda0ff6ed73c67bfb5e62bc9c697f146b7fd7f13
+github.com/containerd/continuity                    f2a389ac0a02ce21c09edd7344677a601970f41c
+github.com/containerd/cgroups                       c4b9ac5c7601384c965b9646fc515884e091ebb9
 github.com/containerd/console                       0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f
 github.com/containerd/console                       0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f
-github.com/containerd/go-runc                       7d11b49dc0769f6dbb0d1b19f3d48524d1bad9ad
+github.com/containerd/go-runc                       e029b79d8cda8374981c64eba71f28ec38e5526f
 github.com/containerd/typeurl                       2a93cfde8c20b23de8eb84a5adbc234ddf7a9e8d
 github.com/containerd/typeurl                       2a93cfde8c20b23de8eb84a5adbc234ddf7a9e8d
 github.com/containerd/ttrpc                         92c8520ef9f86600c650dd540266a007bf03670f
 github.com/containerd/ttrpc                         92c8520ef9f86600c650dd540266a007bf03670f
 github.com/gogo/googleapis                          d31c731455cb061f42baff3bda55bad0118b126b # v1.2.0
 github.com/gogo/googleapis                          d31c731455cb061f42baff3bda55bad0118b126b # v1.2.0
@@ -138,7 +138,7 @@ golang.org/x/crypto                                 88737f569e3a9c7ab309cdc09a07
 golang.org/x/time                                   fbb02b2291d28baffd63558aa44b4b56f178d650
 golang.org/x/time                                   fbb02b2291d28baffd63558aa44b4b56f178d650
 github.com/hashicorp/go-memdb                       cb9a474f84cc5e41b273b20c6927680b2a8776ad
 github.com/hashicorp/go-memdb                       cb9a474f84cc5e41b273b20c6927680b2a8776ad
 github.com/hashicorp/go-immutable-radix             826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git
 github.com/hashicorp/go-immutable-radix             826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git
-github.com/hashicorp/golang-lru                     7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c # v0.5.1
+github.com/hashicorp/golang-lru                     7f827b33c0f158ec5dfbba01bb0b14a4541fd81d # v0.5.3
 github.com/coreos/pkg                               3ac0863d7acf3bc44daf49afef8919af12f704ef # v3
 github.com/coreos/pkg                               3ac0863d7acf3bc44daf49afef8919af12f704ef # v3
 code.cloudfoundry.org/clock                         02e53af36e6c978af692887ed449b74026d76fec
 code.cloudfoundry.org/clock                         02e53af36e6c978af692887ed449b74026d76fec
 
 

+ 1 - 0
vendor/github.com/containerd/cgroups/blkio.go

@@ -86,6 +86,7 @@ func (b *blkioController) Stat(path string, stats *Metrics) error {
 	}
 	}
 	// Try to read CFQ stats available on all CFQ enabled kernels first
 	// Try to read CFQ stats available on all CFQ enabled kernels first
 	if _, err := os.Lstat(filepath.Join(b.Path(path), fmt.Sprintf("blkio.io_serviced_recursive"))); err == nil {
 	if _, err := os.Lstat(filepath.Join(b.Path(path), fmt.Sprintf("blkio.io_serviced_recursive"))); err == nil {
+		settings = []blkioStatSettings{}
 		settings = append(settings,
 		settings = append(settings,
 			blkioStatSettings{
 			blkioStatSettings{
 				name:  "sectors_recursive",
 				name:  "sectors_recursive",

+ 3 - 0
vendor/github.com/containerd/cgroups/cgroup.go

@@ -497,6 +497,9 @@ func (c *cgroup) MoveTo(destination Cgroup) error {
 		}
 		}
 		for _, p := range processes {
 		for _, p := range processes {
 			if err := destination.Add(p); err != nil {
 			if err := destination.Add(p); err != nil {
+				if strings.Contains(err.Error(), "no such process") {
+					continue
+				}
 				return err
 				return err
 			}
 			}
 		}
 		}

+ 4 - 0
vendor/github.com/containerd/cgroups/memory.go

@@ -281,6 +281,10 @@ func getMemorySettings(resources *specs.LinuxResources) []memorySettings {
 			name:  "limit_in_bytes",
 			name:  "limit_in_bytes",
 			value: mem.Limit,
 			value: mem.Limit,
 		},
 		},
+		{
+			name: "soft_limit_in_bytes",
+			value: mem.Reservation,
+		},
 		{
 		{
 			name:  "memsw.limit_in_bytes",
 			name:  "memsw.limit_in_bytes",
 			value: mem.Swap,
 			value: mem.Swap,

+ 531 - 123
vendor/github.com/containerd/cgroups/metrics.pb.go

@@ -1,6 +1,5 @@
-// Code generated by protoc-gen-gogo.
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: github.com/containerd/cgroups/metrics.proto
 // source: github.com/containerd/cgroups/metrics.proto
-// DO NOT EDIT!
 
 
 /*
 /*
 	Package cgroups is a generated protocol buffer package.
 	Package cgroups is a generated protocol buffer package.
@@ -21,6 +20,7 @@
 		BlkIOEntry
 		BlkIOEntry
 		RdmaStat
 		RdmaStat
 		RdmaEntry
 		RdmaEntry
+		NetworkStat
 */
 */
 package cgroups
 package cgroups
 
 
@@ -52,6 +52,7 @@ type Metrics struct {
 	Memory  *MemoryStat    `protobuf:"bytes,4,opt,name=memory" json:"memory,omitempty"`
 	Memory  *MemoryStat    `protobuf:"bytes,4,opt,name=memory" json:"memory,omitempty"`
 	Blkio   *BlkIOStat     `protobuf:"bytes,5,opt,name=blkio" json:"blkio,omitempty"`
 	Blkio   *BlkIOStat     `protobuf:"bytes,5,opt,name=blkio" json:"blkio,omitempty"`
 	Rdma    *RdmaStat      `protobuf:"bytes,6,opt,name=rdma" json:"rdma,omitempty"`
 	Rdma    *RdmaStat      `protobuf:"bytes,6,opt,name=rdma" json:"rdma,omitempty"`
+	Network []*NetworkStat `protobuf:"bytes,7,rep,name=network" json:"network,omitempty"`
 }
 }
 
 
 func (m *Metrics) Reset()                    { *m = Metrics{} }
 func (m *Metrics) Reset()                    { *m = Metrics{} }
@@ -209,6 +210,22 @@ func (m *RdmaEntry) Reset()                    { *m = RdmaEntry{} }
 func (*RdmaEntry) ProtoMessage()               {}
 func (*RdmaEntry) ProtoMessage()               {}
 func (*RdmaEntry) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{11} }
 func (*RdmaEntry) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{11} }
 
 
+type NetworkStat struct {
+	Name      string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	RxBytes   uint64 `protobuf:"varint,2,opt,name=rx_bytes,json=rxBytes,proto3" json:"rx_bytes,omitempty"`
+	RxPackets uint64 `protobuf:"varint,3,opt,name=rx_packets,json=rxPackets,proto3" json:"rx_packets,omitempty"`
+	RxErrors  uint64 `protobuf:"varint,4,opt,name=rx_errors,json=rxErrors,proto3" json:"rx_errors,omitempty"`
+	RxDropped uint64 `protobuf:"varint,5,opt,name=rx_dropped,json=rxDropped,proto3" json:"rx_dropped,omitempty"`
+	TxBytes   uint64 `protobuf:"varint,6,opt,name=tx_bytes,json=txBytes,proto3" json:"tx_bytes,omitempty"`
+	TxPackets uint64 `protobuf:"varint,7,opt,name=tx_packets,json=txPackets,proto3" json:"tx_packets,omitempty"`
+	TxErrors  uint64 `protobuf:"varint,8,opt,name=tx_errors,json=txErrors,proto3" json:"tx_errors,omitempty"`
+	TxDropped uint64 `protobuf:"varint,9,opt,name=tx_dropped,json=txDropped,proto3" json:"tx_dropped,omitempty"`
+}
+
+func (m *NetworkStat) Reset()                    { *m = NetworkStat{} }
+func (*NetworkStat) ProtoMessage()               {}
+func (*NetworkStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{12} }
+
 func init() {
 func init() {
 	proto.RegisterType((*Metrics)(nil), "io.containerd.cgroups.v1.Metrics")
 	proto.RegisterType((*Metrics)(nil), "io.containerd.cgroups.v1.Metrics")
 	proto.RegisterType((*HugetlbStat)(nil), "io.containerd.cgroups.v1.HugetlbStat")
 	proto.RegisterType((*HugetlbStat)(nil), "io.containerd.cgroups.v1.HugetlbStat")
@@ -222,6 +239,7 @@ func init() {
 	proto.RegisterType((*BlkIOEntry)(nil), "io.containerd.cgroups.v1.BlkIOEntry")
 	proto.RegisterType((*BlkIOEntry)(nil), "io.containerd.cgroups.v1.BlkIOEntry")
 	proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v1.RdmaStat")
 	proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v1.RdmaStat")
 	proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v1.RdmaEntry")
 	proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v1.RdmaEntry")
+	proto.RegisterType((*NetworkStat)(nil), "io.containerd.cgroups.v1.NetworkStat")
 }
 }
 func (m *Metrics) Marshal() (dAtA []byte, err error) {
 func (m *Metrics) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
@@ -300,6 +318,18 @@ func (m *Metrics) MarshalTo(dAtA []byte) (int, error) {
 		}
 		}
 		i += n5
 		i += n5
 	}
 	}
+	if len(m.Network) > 0 {
+		for _, msg := range m.Network {
+			dAtA[i] = 0x3a
+			i++
+			i = encodeVarintMetrics(dAtA, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(dAtA[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -389,21 +419,21 @@ func (m *CPUStat) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0xa
 		dAtA[i] = 0xa
 		i++
 		i++
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size()))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size()))
-		n5, err := m.Usage.MarshalTo(dAtA[i:])
+		n6, err := m.Usage.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n5
+		i += n6
 	}
 	}
 	if m.Throttling != nil {
 	if m.Throttling != nil {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Throttling.Size()))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Throttling.Size()))
-		n6, err := m.Throttling.MarshalTo(dAtA[i:])
+		n7, err := m.Throttling.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n6
+		i += n7
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -439,21 +469,21 @@ func (m *CPUUsage) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintMetrics(dAtA, i, uint64(m.User))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.User))
 	}
 	}
 	if len(m.PerCPU) > 0 {
 	if len(m.PerCPU) > 0 {
-		dAtA8 := make([]byte, len(m.PerCPU)*10)
-		var j7 int
+		dAtA9 := make([]byte, len(m.PerCPU)*10)
+		var j8 int
 		for _, num := range m.PerCPU {
 		for _, num := range m.PerCPU {
 			for num >= 1<<7 {
 			for num >= 1<<7 {
-				dAtA8[j7] = uint8(uint64(num)&0x7f | 0x80)
+				dAtA9[j8] = uint8(uint64(num)&0x7f | 0x80)
 				num >>= 7
 				num >>= 7
-				j7++
+				j8++
 			}
 			}
-			dAtA8[j7] = uint8(num)
-			j7++
+			dAtA9[j8] = uint8(num)
+			j8++
 		}
 		}
 		dAtA[i] = 0x22
 		dAtA[i] = 0x22
 		i++
 		i++
-		i = encodeVarintMetrics(dAtA, i, uint64(j7))
-		i += copy(dAtA[i:], dAtA8[:j7])
+		i = encodeVarintMetrics(dAtA, i, uint64(j8))
+		i += copy(dAtA[i:], dAtA9[:j8])
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -706,11 +736,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2
 		dAtA[i] = 0x2
 		i++
 		i++
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size()))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size()))
-		n9, err := m.Usage.MarshalTo(dAtA[i:])
+		n10, err := m.Usage.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n9
+		i += n10
 	}
 	}
 	if m.Swap != nil {
 	if m.Swap != nil {
 		dAtA[i] = 0x92
 		dAtA[i] = 0x92
@@ -718,11 +748,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2
 		dAtA[i] = 0x2
 		i++
 		i++
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Swap.Size()))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Swap.Size()))
-		n10, err := m.Swap.MarshalTo(dAtA[i:])
+		n11, err := m.Swap.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n10
+		i += n11
 	}
 	}
 	if m.Kernel != nil {
 	if m.Kernel != nil {
 		dAtA[i] = 0x9a
 		dAtA[i] = 0x9a
@@ -730,11 +760,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2
 		dAtA[i] = 0x2
 		i++
 		i++
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Kernel.Size()))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.Kernel.Size()))
-		n11, err := m.Kernel.MarshalTo(dAtA[i:])
+		n12, err := m.Kernel.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n11
+		i += n12
 	}
 	}
 	if m.KernelTCP != nil {
 	if m.KernelTCP != nil {
 		dAtA[i] = 0xa2
 		dAtA[i] = 0xa2
@@ -742,11 +772,11 @@ func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2
 		dAtA[i] = 0x2
 		i++
 		i++
 		i = encodeVarintMetrics(dAtA, i, uint64(m.KernelTCP.Size()))
 		i = encodeVarintMetrics(dAtA, i, uint64(m.KernelTCP.Size()))
-		n12, err := m.KernelTCP.MarshalTo(dAtA[i:])
+		n13, err := m.KernelTCP.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n12
+		i += n13
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -766,7 +796,6 @@ func (m *MemoryEntry) MarshalTo(dAtA []byte) (int, error) {
 	_ = i
 	_ = i
 	var l int
 	var l int
 	_ = l
 	_ = l
-
 	if m.Limit != 0 {
 	if m.Limit != 0 {
 		dAtA[i] = 0x8
 		dAtA[i] = 0x8
 		i++
 		i++
@@ -1025,24 +1054,70 @@ func (m *RdmaEntry) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 	return i, nil
 }
 }
 
 
-func encodeFixed64Metrics(dAtA []byte, offset int, v uint64) int {
-	dAtA[offset] = uint8(v)
-	dAtA[offset+1] = uint8(v >> 8)
-	dAtA[offset+2] = uint8(v >> 16)
-	dAtA[offset+3] = uint8(v >> 24)
-	dAtA[offset+4] = uint8(v >> 32)
-	dAtA[offset+5] = uint8(v >> 40)
-	dAtA[offset+6] = uint8(v >> 48)
-	dAtA[offset+7] = uint8(v >> 56)
-	return offset + 8
+func (m *NetworkStat) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
 }
 }
-func encodeFixed32Metrics(dAtA []byte, offset int, v uint32) int {
-	dAtA[offset] = uint8(v)
-	dAtA[offset+1] = uint8(v >> 8)
-	dAtA[offset+2] = uint8(v >> 16)
-	dAtA[offset+3] = uint8(v >> 24)
-	return offset + 4
+
+func (m *NetworkStat) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Name) > 0 {
+		dAtA[i] = 0xa
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(len(m.Name)))
+		i += copy(dAtA[i:], m.Name)
+	}
+	if m.RxBytes != 0 {
+		dAtA[i] = 0x10
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.RxBytes))
+	}
+	if m.RxPackets != 0 {
+		dAtA[i] = 0x18
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.RxPackets))
+	}
+	if m.RxErrors != 0 {
+		dAtA[i] = 0x20
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.RxErrors))
+	}
+	if m.RxDropped != 0 {
+		dAtA[i] = 0x28
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.RxDropped))
+	}
+	if m.TxBytes != 0 {
+		dAtA[i] = 0x30
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.TxBytes))
+	}
+	if m.TxPackets != 0 {
+		dAtA[i] = 0x38
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.TxPackets))
+	}
+	if m.TxErrors != 0 {
+		dAtA[i] = 0x40
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.TxErrors))
+	}
+	if m.TxDropped != 0 {
+		dAtA[i] = 0x48
+		i++
+		i = encodeVarintMetrics(dAtA, i, uint64(m.TxDropped))
+	}
+	return i, nil
 }
 }
+
 func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int {
 func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int {
 	for v >= 1<<7 {
 	for v >= 1<<7 {
 		dAtA[offset] = uint8(v&0x7f | 0x80)
 		dAtA[offset] = uint8(v&0x7f | 0x80)
@@ -1081,6 +1156,12 @@ func (m *Metrics) Size() (n int) {
 		l = m.Rdma.Size()
 		l = m.Rdma.Size()
 		n += 1 + l + sovMetrics(uint64(l))
 		n += 1 + l + sovMetrics(uint64(l))
 	}
 	}
+	if len(m.Network) > 0 {
+		for _, e := range m.Network {
+			l = e.Size()
+			n += 1 + l + sovMetrics(uint64(l))
+		}
+	}
 	return n
 	return n
 }
 }
 
 
@@ -1413,6 +1494,40 @@ func (m *RdmaEntry) Size() (n int) {
 	return n
 	return n
 }
 }
 
 
+func (m *NetworkStat) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.Name)
+	if l > 0 {
+		n += 1 + l + sovMetrics(uint64(l))
+	}
+	if m.RxBytes != 0 {
+		n += 1 + sovMetrics(uint64(m.RxBytes))
+	}
+	if m.RxPackets != 0 {
+		n += 1 + sovMetrics(uint64(m.RxPackets))
+	}
+	if m.RxErrors != 0 {
+		n += 1 + sovMetrics(uint64(m.RxErrors))
+	}
+	if m.RxDropped != 0 {
+		n += 1 + sovMetrics(uint64(m.RxDropped))
+	}
+	if m.TxBytes != 0 {
+		n += 1 + sovMetrics(uint64(m.TxBytes))
+	}
+	if m.TxPackets != 0 {
+		n += 1 + sovMetrics(uint64(m.TxPackets))
+	}
+	if m.TxErrors != 0 {
+		n += 1 + sovMetrics(uint64(m.TxErrors))
+	}
+	if m.TxDropped != 0 {
+		n += 1 + sovMetrics(uint64(m.TxDropped))
+	}
+	return n
+}
+
 func sovMetrics(x uint64) (n int) {
 func sovMetrics(x uint64) (n int) {
 	for {
 	for {
 		n++
 		n++
@@ -1437,6 +1552,7 @@ func (this *Metrics) String() string {
 		`Memory:` + strings.Replace(fmt.Sprintf("%v", this.Memory), "MemoryStat", "MemoryStat", 1) + `,`,
 		`Memory:` + strings.Replace(fmt.Sprintf("%v", this.Memory), "MemoryStat", "MemoryStat", 1) + `,`,
 		`Blkio:` + strings.Replace(fmt.Sprintf("%v", this.Blkio), "BlkIOStat", "BlkIOStat", 1) + `,`,
 		`Blkio:` + strings.Replace(fmt.Sprintf("%v", this.Blkio), "BlkIOStat", "BlkIOStat", 1) + `,`,
 		`Rdma:` + strings.Replace(fmt.Sprintf("%v", this.Rdma), "RdmaStat", "RdmaStat", 1) + `,`,
 		`Rdma:` + strings.Replace(fmt.Sprintf("%v", this.Rdma), "RdmaStat", "RdmaStat", 1) + `,`,
+		`Network:` + strings.Replace(fmt.Sprintf("%v", this.Network), "NetworkStat", "NetworkStat", 1) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
@@ -1613,6 +1729,24 @@ func (this *RdmaEntry) String() string {
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
+func (this *NetworkStat) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&NetworkStat{`,
+		`Name:` + fmt.Sprintf("%v", this.Name) + `,`,
+		`RxBytes:` + fmt.Sprintf("%v", this.RxBytes) + `,`,
+		`RxPackets:` + fmt.Sprintf("%v", this.RxPackets) + `,`,
+		`RxErrors:` + fmt.Sprintf("%v", this.RxErrors) + `,`,
+		`RxDropped:` + fmt.Sprintf("%v", this.RxDropped) + `,`,
+		`TxBytes:` + fmt.Sprintf("%v", this.TxBytes) + `,`,
+		`TxPackets:` + fmt.Sprintf("%v", this.TxPackets) + `,`,
+		`TxErrors:` + fmt.Sprintf("%v", this.TxErrors) + `,`,
+		`TxDropped:` + fmt.Sprintf("%v", this.TxDropped) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func valueToStringMetrics(v interface{}) string {
 func valueToStringMetrics(v interface{}) string {
 	rv := reflect.ValueOf(v)
 	rv := reflect.ValueOf(v)
 	if rv.IsNil() {
 	if rv.IsNil() {
@@ -1624,7 +1758,6 @@ func valueToStringMetrics(v interface{}) string {
 func (m *Metrics) Unmarshal(dAtA []byte) error {
 func (m *Metrics) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0
-
 	for iNdEx < l {
 	for iNdEx < l {
 		preIndex := iNdEx
 		preIndex := iNdEx
 		var wire uint64
 		var wire uint64
@@ -1847,6 +1980,37 @@ func (m *Metrics) Unmarshal(dAtA []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			iNdEx = postIndex
+		case 7:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Network", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthMetrics
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Network = append(m.Network, &NetworkStat{})
+			if err := m.Network[len(m.Network)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipMetrics(dAtA[iNdEx:])
 			skippy, err := skipMetrics(dAtA[iNdEx:])
@@ -4092,7 +4256,237 @@ func (m *RdmaEntry) Unmarshal(dAtA []byte) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+func (m *NetworkStat) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowMetrics
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: NetworkStat: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: NetworkStat: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthMetrics
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Name = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RxBytes", wireType)
+			}
+			m.RxBytes = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.RxBytes |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RxPackets", wireType)
+			}
+			m.RxPackets = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.RxPackets |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 4:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RxErrors", wireType)
+			}
+			m.RxErrors = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.RxErrors |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 5:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RxDropped", wireType)
+			}
+			m.RxDropped = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.RxDropped |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 6:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field TxBytes", wireType)
+			}
+			m.TxBytes = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.TxBytes |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 7:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field TxPackets", wireType)
+			}
+			m.TxPackets = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.TxPackets |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 8:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field TxErrors", wireType)
+			}
+			m.TxErrors = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.TxErrors |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 9:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field TxDropped", wireType)
+			}
+			m.TxDropped = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowMetrics
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.TxDropped |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		default:
+			iNdEx = preIndex
+			skippy, err := skipMetrics(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthMetrics
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
 
 
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func skipMetrics(dAtA []byte) (n int, err error) {
 func skipMetrics(dAtA []byte) (n int, err error) {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0
@@ -4201,88 +4595,102 @@ var (
 func init() { proto.RegisterFile("github.com/containerd/cgroups/metrics.proto", fileDescriptorMetrics) }
 func init() { proto.RegisterFile("github.com/containerd/cgroups/metrics.proto", fileDescriptorMetrics) }
 
 
 var fileDescriptorMetrics = []byte{
 var fileDescriptorMetrics = []byte{
-	// 1325 bytes of a gzipped FileDescriptorProto
+	// 1549 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x4d, 0x6f, 0x1b, 0xb7,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x4d, 0x6f, 0x1b, 0xb7,
-	0x16, 0x8d, 0xac, 0xb1, 0x3e, 0xae, 0x6c, 0xc7, 0xa6, 0x13, 0x67, 0xec, 0x97, 0x27, 0x29, 0xb2,
-	0xfd, 0x9e, 0x5b, 0x03, 0x32, 0x9a, 0x02, 0x41, 0x93, 0xa6, 0x28, 0x22, 0xb7, 0x41, 0x83, 0xd6,
-	0x88, 0x32, 0xb2, 0x91, 0x76, 0x35, 0x18, 0x8d, 0x98, 0x31, 0xe3, 0xd1, 0x70, 0xc2, 0xe1, 0xc8,
-	0x71, 0x57, 0xdd, 0xf5, 0x37, 0xf5, 0x1f, 0x64, 0xd9, 0x4d, 0x81, 0x76, 0x63, 0x34, 0xfa, 0x25,
-	0x05, 0x2f, 0xe7, 0x4b, 0x49, 0xdc, 0x40, 0xbb, 0xb9, 0xbc, 0xe7, 0x1c, 0x5e, 0x5e, 0x1e, 0x8a,
-	0x14, 0xec, 0x7b, 0x4c, 0x9e, 0xc6, 0xc3, 0xae, 0xcb, 0xc7, 0x07, 0x2e, 0x0f, 0xa4, 0xc3, 0x02,
-	0x2a, 0x46, 0x07, 0xae, 0x27, 0x78, 0x1c, 0x46, 0x07, 0x63, 0x2a, 0x05, 0x73, 0xa3, 0x6e, 0x28,
-	0xb8, 0xe4, 0xc4, 0x64, 0xbc, 0x9b, 0x83, 0xba, 0x09, 0xa8, 0x3b, 0xf9, 0x6c, 0xeb, 0x86, 0xc7,
-	0x3d, 0x8e, 0xa0, 0x03, 0xf5, 0xa5, 0xf1, 0x9d, 0xdf, 0x16, 0xa0, 0x7a, 0xa4, 0x15, 0xc8, 0xd7,
-	0x50, 0x3d, 0x8d, 0x3d, 0x2a, 0xfd, 0xa1, 0x59, 0x6a, 0x97, 0xf7, 0x1a, 0x77, 0x77, 0xbb, 0x57,
-	0xa9, 0x75, 0xbf, 0xd3, 0xc0, 0x81, 0x74, 0xa4, 0x95, 0xb2, 0xc8, 0x3d, 0x30, 0x42, 0x36, 0x8a,
-	0xcc, 0x85, 0x76, 0x69, 0xaf, 0x71, 0xb7, 0x73, 0x35, 0xbb, 0xcf, 0x46, 0x11, 0x52, 0x11, 0x4f,
-	0x1e, 0x42, 0xd9, 0x0d, 0x63, 0xb3, 0x8c, 0xb4, 0x3b, 0x57, 0xd3, 0x0e, 0xfb, 0x27, 0x8a, 0xd5,
-	0xab, 0x4e, 0x2f, 0x5b, 0xe5, 0xc3, 0xfe, 0x89, 0xa5, 0x68, 0xe4, 0x21, 0x54, 0xc6, 0x74, 0xcc,
-	0xc5, 0x85, 0x69, 0xa0, 0xc0, 0xce, 0xd5, 0x02, 0x47, 0x88, 0xc3, 0x99, 0x13, 0x0e, 0xb9, 0x0f,
-	0x8b, 0x43, 0xff, 0x8c, 0x71, 0x73, 0x11, 0xc9, 0xdb, 0x57, 0x93, 0x7b, 0xfe, 0xd9, 0x93, 0xa7,
-	0xc8, 0xd5, 0x8c, 0xce, 0x19, 0x34, 0x0a, 0x6d, 0x20, 0x37, 0x60, 0x31, 0x8e, 0x1c, 0x8f, 0x9a,
-	0xa5, 0x76, 0x69, 0xcf, 0xb0, 0x74, 0x40, 0x56, 0xa1, 0x3c, 0x76, 0x5e, 0x63, 0x4b, 0x0c, 0x4b,
-	0x7d, 0x12, 0x13, 0xaa, 0x2f, 0x1c, 0xe6, 0xbb, 0x81, 0xc4, 0x15, 0x1b, 0x56, 0x1a, 0x92, 0x2d,
-	0xa8, 0x85, 0x8e, 0x47, 0x23, 0xf6, 0x33, 0xc5, 0xb5, 0xd4, 0xad, 0x2c, 0xee, 0x3c, 0x80, 0x5a,
-	0xda, 0x35, 0xa5, 0xe0, 0xc6, 0x42, 0xd0, 0x40, 0x26, 0x73, 0xa5, 0xa1, 0xaa, 0xc1, 0x67, 0x63,
-	0x26, 0x93, 0xf9, 0x74, 0xd0, 0xf9, 0xb5, 0x04, 0xd5, 0xa4, 0x77, 0xe4, 0x8b, 0x62, 0x95, 0xff,
-	0xba, 0x49, 0x87, 0xfd, 0x93, 0x13, 0x85, 0x4c, 0x57, 0xd2, 0x03, 0x90, 0xa7, 0x82, 0x4b, 0xe9,
-	0xb3, 0xc0, 0xfb, 0xf8, 0x1e, 0x1f, 0x6b, 0x2c, 0xb5, 0x0a, 0xac, 0xce, 0x2b, 0xa8, 0xa5, 0xb2,
-	0xaa, 0x56, 0xc9, 0xa5, 0xe3, 0xa7, 0xfd, 0xc2, 0x80, 0x6c, 0x40, 0xe5, 0x8c, 0x8a, 0x80, 0xfa,
-	0xc9, 0x12, 0x92, 0x88, 0x10, 0x30, 0xe2, 0x88, 0x8a, 0xa4, 0x65, 0xf8, 0x4d, 0xb6, 0xa1, 0x1a,
-	0x52, 0x61, 0x2b, 0xef, 0x18, 0xed, 0xf2, 0x9e, 0xd1, 0x83, 0xe9, 0x65, 0xab, 0xd2, 0xa7, 0x42,
-	0x79, 0xa3, 0x12, 0x52, 0x71, 0x18, 0xc6, 0x9d, 0xd7, 0x50, 0x4b, 0x4b, 0x51, 0x8d, 0x0b, 0xa9,
-	0x60, 0x7c, 0x14, 0xa5, 0x8d, 0x4b, 0x42, 0xb2, 0x0f, 0x6b, 0x49, 0x99, 0x74, 0x64, 0xa7, 0x18,
-	0x5d, 0xc1, 0x6a, 0x96, 0xe8, 0x27, 0xe0, 0x5d, 0x58, 0xc9, 0xc1, 0x92, 0x8d, 0x69, 0x52, 0xd5,
-	0x72, 0x36, 0x7a, 0xcc, 0xc6, 0xb4, 0xf3, 0x57, 0x03, 0x20, 0x77, 0x9c, 0x5a, 0xaf, 0xeb, 0xb8,
-	0xa7, 0x99, 0x3f, 0x30, 0x20, 0x9b, 0x50, 0x16, 0x51, 0x32, 0x95, 0x36, 0xb6, 0x35, 0x18, 0x58,
-	0x6a, 0x8c, 0xfc, 0x0f, 0x6a, 0x22, 0x8a, 0x6c, 0x75, 0xba, 0xf4, 0x04, 0xbd, 0xc6, 0xf4, 0xb2,
-	0x55, 0xb5, 0x06, 0x03, 0x65, 0x3b, 0xab, 0x2a, 0xa2, 0x48, 0x7d, 0x90, 0x16, 0x34, 0xc6, 0x4e,
-	0x18, 0xd2, 0x91, 0xfd, 0x82, 0xf9, 0xda, 0x39, 0x86, 0x05, 0x7a, 0xe8, 0x31, 0xf3, 0xb1, 0xd3,
-	0x23, 0x26, 0xe4, 0x05, 0x7a, 0xdc, 0xb0, 0x74, 0x40, 0x6e, 0x43, 0xfd, 0x5c, 0x30, 0x49, 0x87,
-	0x8e, 0x7b, 0x66, 0x56, 0x30, 0x93, 0x0f, 0x10, 0x13, 0x6a, 0xa1, 0x67, 0x87, 0x9e, 0xcd, 0x02,
-	0xb3, 0xaa, 0x77, 0x22, 0xf4, 0xfa, 0xde, 0x93, 0x80, 0x6c, 0x41, 0x5d, 0x67, 0x78, 0x2c, 0xcd,
-	0x5a, 0xd2, 0x46, 0xaf, 0xef, 0x3d, 0x8d, 0x25, 0xd9, 0x44, 0xd6, 0x0b, 0x27, 0xf6, 0xa5, 0x59,
-	0x4f, 0x53, 0x8f, 0x55, 0x48, 0xda, 0xb0, 0x14, 0x7a, 0xf6, 0xd8, 0x79, 0x99, 0xa4, 0x41, 0x97,
-	0x19, 0x7a, 0x47, 0xce, 0x4b, 0x8d, 0xd8, 0x86, 0x65, 0x16, 0x38, 0xae, 0x64, 0x13, 0x6a, 0x3b,
-	0x01, 0x0f, 0xcc, 0x06, 0x42, 0x96, 0xd2, 0xc1, 0x47, 0x01, 0x0f, 0xd4, 0x62, 0x8b, 0x90, 0x25,
-	0xad, 0x52, 0x00, 0x14, 0x55, 0xb0, 0x1f, 0xcb, 0xb3, 0x2a, 0xd8, 0x91, 0x5c, 0x05, 0x21, 0x2b,
-	0x45, 0x15, 0x04, 0xb4, 0xa1, 0x11, 0x07, 0x74, 0xc2, 0x5c, 0xe9, 0x0c, 0x7d, 0x6a, 0x5e, 0x47,
-	0x40, 0x71, 0x88, 0x3c, 0x80, 0xcd, 0x53, 0x46, 0x85, 0x23, 0xdc, 0x53, 0xe6, 0x3a, 0xbe, 0xad,
-	0x7f, 0x4f, 0x6c, 0x7d, 0xfc, 0x56, 0x11, 0x7f, 0xab, 0x08, 0xd0, 0x4e, 0xf8, 0x41, 0xa5, 0xc9,
-	0x3d, 0x98, 0x49, 0xd9, 0xd1, 0xb9, 0x13, 0x26, 0xcc, 0x35, 0x64, 0xde, 0x2c, 0xa6, 0x07, 0xe7,
-	0x4e, 0xa8, 0x79, 0x2d, 0x68, 0xe0, 0x29, 0xb1, 0xb5, 0x91, 0x88, 0x2e, 0x1b, 0x87, 0x0e, 0xd1,
-	0x4d, 0x9f, 0x40, 0x5d, 0x03, 0x94, 0xa7, 0xd6, 0xd1, 0x33, 0x4b, 0xd3, 0xcb, 0x56, 0xed, 0x58,
-	0x0d, 0x2a, 0x63, 0xd5, 0x30, 0x6d, 0x45, 0x11, 0xb9, 0x07, 0x2b, 0x19, 0x54, 0x7b, 0xec, 0x06,
-	0xe2, 0x57, 0xa7, 0x97, 0xad, 0xa5, 0x14, 0x8f, 0x46, 0x5b, 0x4a, 0x39, 0xe8, 0xb6, 0x4f, 0x61,
-	0x4d, 0xf3, 0x8a, 0x9e, 0xbb, 0x89, 0x95, 0x5c, 0xc7, 0xc4, 0x51, 0x6e, 0xbc, 0xac, 0x5e, 0x6d,
-	0xbf, 0x8d, 0x42, 0xbd, 0xdf, 0xa0, 0x07, 0xff, 0x0f, 0x9a, 0x63, 0xe7, 0x4e, 0xbc, 0x85, 0x20,
-	0x5d, 0xdb, 0xf3, 0xcc, 0x8e, 0xdb, 0x69, 0xb5, 0x99, 0x29, 0x4d, 0xbd, 0x25, 0x38, 0xda, 0xd7,
-	0xce, 0xdc, 0x4d, 0xd5, 0x72, 0x7f, 0x6e, 0xea, 0xcd, 0xcf, 0x50, 0xca, 0xa4, 0x3b, 0x05, 0x2d,
-	0xed, 0xc5, 0xad, 0x19, 0x94, 0x76, 0xe3, 0x3e, 0x90, 0x0c, 0x95, 0xbb, 0xf6, 0x3f, 0x85, 0x85,
-	0xf6, 0x73, 0xeb, 0x76, 0x61, 0x5d, 0x83, 0x67, 0x0d, 0x7c, 0x1b, 0xd1, 0xba, 0x5f, 0x4f, 0x8a,
-	0x2e, 0xce, 0x9a, 0x58, 0x44, 0xff, 0xb7, 0xa0, 0xfd, 0x28, 0xc7, 0xbe, 0xaf, 0x8d, 0x2d, 0x6f,
-	0x7e, 0x40, 0x1b, 0x9b, 0xfe, 0xae, 0x36, 0xa2, 0x5b, 0xef, 0x69, 0x23, 0x76, 0x3f, 0xc5, 0x16,
-	0xcd, 0xde, 0x4e, 0x7e, 0xf6, 0x54, 0xe2, 0xa4, 0xe0, 0xf8, 0x2f, 0xd3, 0xab, 0xe3, 0x0e, 0xfe,
-	0xf6, 0xef, 0x7e, 0xec, 0x9e, 0xfd, 0x36, 0x90, 0xe2, 0x22, 0xbd, 0x3d, 0xee, 0x83, 0xa1, 0x5c,
-	0x6e, 0x76, 0xe6, 0xe1, 0x22, 0x85, 0x7c, 0x95, 0x5d, 0x09, 0xdb, 0xf3, 0x90, 0xd3, 0x9b, 0x63,
-	0x00, 0xa0, 0xbf, 0x6c, 0xe9, 0x86, 0xe6, 0xce, 0x1c, 0x12, 0xbd, 0xe5, 0xe9, 0x65, 0xab, 0xfe,
-	0x3d, 0x92, 0x8f, 0x0f, 0xfb, 0x56, 0x5d, 0xeb, 0x1c, 0xbb, 0x61, 0x87, 0x42, 0xa3, 0x00, 0xcc,
-	0xef, 0xdd, 0x52, 0xe1, 0xde, 0xcd, 0x5f, 0x04, 0x0b, 0x1f, 0x78, 0x11, 0x94, 0x3f, 0xf8, 0x22,
-	0x30, 0x66, 0x5e, 0x04, 0x9d, 0x3f, 0x16, 0xa1, 0x9e, 0xbd, 0x3b, 0x88, 0x03, 0x5b, 0x8c, 0xdb,
-	0x11, 0x15, 0x13, 0xe6, 0x52, 0x7b, 0x78, 0x21, 0x69, 0x64, 0x0b, 0xea, 0xc6, 0x22, 0x62, 0x13,
-	0x9a, 0xbc, 0xd9, 0x76, 0x3e, 0xf2, 0x80, 0xd1, 0xbd, 0xb9, 0xc5, 0xf8, 0x40, 0xcb, 0xf4, 0x94,
-	0x8a, 0x95, 0x8a, 0x90, 0x1f, 0xe1, 0x66, 0x3e, 0xc5, 0xa8, 0xa0, 0xbe, 0x30, 0x87, 0xfa, 0x7a,
-	0xa6, 0x3e, 0xca, 0x95, 0x8f, 0x61, 0x9d, 0x71, 0xfb, 0x55, 0x4c, 0xe3, 0x19, 0xdd, 0xf2, 0x1c,
-	0xba, 0x6b, 0x8c, 0x3f, 0x43, 0x7e, 0xae, 0x6a, 0xc3, 0x66, 0xa1, 0x25, 0xea, 0x2e, 0x2e, 0x68,
-	0x1b, 0x73, 0x68, 0x6f, 0x64, 0x35, 0xab, 0xbb, 0x3b, 0x9f, 0xe0, 0x27, 0xd8, 0x60, 0xdc, 0x3e,
-	0x77, 0x98, 0x7c, 0x57, 0x7d, 0x71, 0xbe, 0x8e, 0x3c, 0x77, 0x98, 0x9c, 0x95, 0xd6, 0x1d, 0x19,
-	0x53, 0xe1, 0xcd, 0x74, 0xa4, 0x32, 0x5f, 0x47, 0x8e, 0x90, 0x9f, 0xab, 0xf6, 0x61, 0x8d, 0xf1,
-	0x77, 0x6b, 0xad, 0xce, 0xa1, 0x79, 0x9d, 0xf1, 0xd9, 0x3a, 0x9f, 0xc1, 0x5a, 0x44, 0x5d, 0xc9,
-	0x45, 0xd1, 0x6d, 0xb5, 0x39, 0x14, 0x57, 0x13, 0x7a, 0x26, 0xd9, 0x99, 0x00, 0xe4, 0x79, 0xb2,
-	0x02, 0x0b, 0x3c, 0xc4, 0xa3, 0x53, 0xb7, 0x16, 0x78, 0xa8, 0xde, 0x80, 0x23, 0xf5, 0xb3, 0xa3,
-	0x0f, 0x4e, 0xdd, 0x4a, 0x22, 0x75, 0x9e, 0xc6, 0xce, 0x4b, 0x9e, 0x3e, 0x02, 0x75, 0x80, 0xa3,
-	0x2c, 0xe0, 0x22, 0x39, 0x3b, 0x3a, 0x50, 0xa3, 0x13, 0xc7, 0x8f, 0x69, 0xfa, 0xe6, 0xc1, 0xa0,
-	0x67, 0xbe, 0x79, 0xdb, 0xbc, 0xf6, 0xe7, 0xdb, 0xe6, 0xb5, 0x5f, 0xa6, 0xcd, 0xd2, 0x9b, 0x69,
-	0xb3, 0xf4, 0xfb, 0xb4, 0x59, 0xfa, 0x7b, 0xda, 0x2c, 0x0d, 0x2b, 0xf8, 0x7f, 0xe8, 0xf3, 0x7f,
-	0x02, 0x00, 0x00, 0xff, 0xff, 0xb2, 0x21, 0x0b, 0xcd, 0x6e, 0x0d, 0x00, 0x00,
+	0x16, 0x8d, 0x2c, 0xd9, 0xd2, 0x5c, 0xd9, 0x8e, 0x4d, 0x27, 0xce, 0xd8, 0x49, 0x2c, 0x47, 0xb6,
+	0xdf, 0xf3, 0x7b, 0x06, 0x64, 0xbc, 0x3c, 0x20, 0x68, 0xd2, 0x04, 0x45, 0xe4, 0x24, 0x48, 0xd0,
+	0xba, 0x51, 0x46, 0x36, 0xd2, 0xae, 0x06, 0xd4, 0x88, 0x19, 0xd1, 0x96, 0x86, 0x13, 0x0e, 0xc7,
+	0x96, 0xbb, 0xea, 0xa2, 0x40, 0x57, 0xfd, 0x33, 0xfd, 0x15, 0x59, 0x76, 0x53, 0xa0, 0xdd, 0x18,
+	0x8d, 0x7e, 0x49, 0x41, 0x72, 0x3e, 0xa8, 0x24, 0x8e, 0xab, 0xdd, 0x90, 0x3c, 0xe7, 0xdc, 0xcb,
+	0x3b, 0x87, 0xc3, 0x3b, 0xb0, 0xe3, 0x53, 0xd1, 0x8b, 0x3b, 0x0d, 0x8f, 0x0d, 0x76, 0x3d, 0x16,
+	0x08, 0x4c, 0x03, 0xc2, 0xbb, 0xbb, 0x9e, 0xcf, 0x59, 0x1c, 0x46, 0xbb, 0x03, 0x22, 0x38, 0xf5,
+	0xa2, 0x46, 0xc8, 0x99, 0x60, 0xc8, 0xa6, 0xac, 0x91, 0x83, 0x1a, 0x09, 0xa8, 0x71, 0xf2, 0xbf,
+	0xd5, 0x6b, 0x3e, 0xf3, 0x99, 0x02, 0xed, 0xca, 0x27, 0x8d, 0xaf, 0xff, 0x5a, 0x84, 0xf2, 0xbe,
+	0x56, 0x40, 0x5f, 0x41, 0xb9, 0x17, 0xfb, 0x44, 0xf4, 0x3b, 0x76, 0x61, 0xbd, 0xb8, 0x5d, 0xbd,
+	0xbb, 0xd5, 0xb8, 0x48, 0xad, 0xf1, 0x5c, 0x03, 0xdb, 0x02, 0x0b, 0x27, 0x65, 0xa1, 0x7b, 0x50,
+	0x0a, 0x69, 0x37, 0xb2, 0xa7, 0xd6, 0x0b, 0xdb, 0xd5, 0xbb, 0xf5, 0x8b, 0xd9, 0x2d, 0xda, 0x8d,
+	0x14, 0x55, 0xe1, 0xd1, 0x43, 0x28, 0x7a, 0x61, 0x6c, 0x17, 0x15, 0xed, 0xce, 0xc5, 0xb4, 0xbd,
+	0xd6, 0xa1, 0x64, 0x35, 0xcb, 0xa3, 0xf3, 0x5a, 0x71, 0xaf, 0x75, 0xe8, 0x48, 0x1a, 0x7a, 0x08,
+	0x33, 0x03, 0x32, 0x60, 0xfc, 0xcc, 0x2e, 0x29, 0x81, 0xcd, 0x8b, 0x05, 0xf6, 0x15, 0x4e, 0x45,
+	0x4e, 0x38, 0xe8, 0x3e, 0x4c, 0x77, 0xfa, 0xc7, 0x94, 0xd9, 0xd3, 0x8a, 0xbc, 0x71, 0x31, 0xb9,
+	0xd9, 0x3f, 0x7e, 0xf1, 0x52, 0x71, 0x35, 0x43, 0x6e, 0x97, 0x77, 0x07, 0xd8, 0x9e, 0xb9, 0x6c,
+	0xbb, 0x4e, 0x77, 0x80, 0xf5, 0x76, 0x25, 0x5e, 0xd6, 0x39, 0x20, 0xe2, 0x94, 0xf1, 0x63, 0xbb,
+	0x7c, 0x59, 0x9d, 0xbf, 0xd5, 0x40, 0x5d, 0xe7, 0x84, 0x55, 0x3f, 0x86, 0xaa, 0x51, 0x7f, 0x74,
+	0x0d, 0xa6, 0xe3, 0x08, 0xfb, 0xc4, 0x2e, 0xac, 0x17, 0xb6, 0x4b, 0x8e, 0x1e, 0xa0, 0x05, 0x28,
+	0x0e, 0xf0, 0x50, 0xbd, 0x8b, 0x92, 0x23, 0x1f, 0x91, 0x0d, 0xe5, 0x37, 0x98, 0xf6, 0xbd, 0x40,
+	0xa8, 0x52, 0x97, 0x9c, 0x74, 0x88, 0x56, 0xa1, 0x12, 0x62, 0x9f, 0x44, 0xf4, 0x07, 0xa2, 0x8a,
+	0x68, 0x39, 0xd9, 0xb8, 0xfe, 0x00, 0x2a, 0xe9, 0xeb, 0x92, 0x0a, 0x5e, 0xcc, 0x39, 0x09, 0x44,
+	0x12, 0x2b, 0x1d, 0xca, 0x1c, 0xfa, 0x74, 0x40, 0x45, 0x12, 0x4f, 0x0f, 0xea, 0x3f, 0x17, 0xa0,
+	0x9c, 0xbc, 0x34, 0xf4, 0x85, 0x99, 0xe5, 0x67, 0xcb, 0xb5, 0xd7, 0x3a, 0x3c, 0x94, 0xc8, 0x74,
+	0x27, 0x4d, 0x00, 0xd1, 0xe3, 0x4c, 0x88, 0x3e, 0x0d, 0xfc, 0xcb, 0xcd, 0x75, 0xa0, 0xb1, 0xc4,
+	0x31, 0x58, 0xf5, 0xb7, 0x50, 0x49, 0x65, 0x65, 0xae, 0x82, 0x09, 0xdc, 0x4f, 0xeb, 0xa5, 0x06,
+	0x68, 0x19, 0x66, 0x8e, 0x09, 0x0f, 0x48, 0x3f, 0xd9, 0x42, 0x32, 0x42, 0x08, 0x4a, 0x71, 0x44,
+	0x78, 0x52, 0x32, 0xf5, 0x8c, 0x36, 0xa0, 0x1c, 0x12, 0xee, 0x4a, 0xd3, 0x96, 0xd6, 0x8b, 0xdb,
+	0xa5, 0x26, 0x8c, 0xce, 0x6b, 0x33, 0x2d, 0xc2, 0xa5, 0x29, 0x67, 0x42, 0xc2, 0xf7, 0xc2, 0xb8,
+	0x3e, 0x84, 0x4a, 0x9a, 0x8a, 0x2c, 0x5c, 0x48, 0x38, 0x65, 0xdd, 0x28, 0x2d, 0x5c, 0x32, 0x44,
+	0x3b, 0xb0, 0x98, 0xa4, 0x49, 0xba, 0x6e, 0x8a, 0xd1, 0x19, 0x2c, 0x64, 0x0b, 0xad, 0x04, 0xbc,
+	0x05, 0xf3, 0x39, 0x58, 0xd0, 0x01, 0x49, 0xb2, 0x9a, 0xcb, 0x66, 0x0f, 0xe8, 0x80, 0xd4, 0xff,
+	0xac, 0x02, 0xe4, 0x56, 0x97, 0xfb, 0xf5, 0xb0, 0xd7, 0xcb, 0xfc, 0xa1, 0x06, 0x68, 0x05, 0x8a,
+	0x3c, 0x4a, 0x42, 0xe9, 0x13, 0xe5, 0xb4, 0xdb, 0x8e, 0x9c, 0x43, 0xff, 0x82, 0x0a, 0x8f, 0x22,
+	0x57, 0x1e, 0x6b, 0x1d, 0xa0, 0x59, 0x1d, 0x9d, 0xd7, 0xca, 0x4e, 0xbb, 0x2d, 0x6d, 0xe7, 0x94,
+	0x79, 0x14, 0xc9, 0x07, 0x54, 0x83, 0xea, 0x00, 0x87, 0x21, 0xe9, 0xba, 0x6f, 0x68, 0x5f, 0x3b,
+	0xa7, 0xe4, 0x80, 0x9e, 0x7a, 0x46, 0xfb, 0xaa, 0xd2, 0x5d, 0xca, 0xc5, 0x99, 0x3a, 0x5c, 0x25,
+	0x47, 0x0f, 0xd0, 0x2d, 0xb0, 0x4e, 0x39, 0x15, 0xa4, 0x83, 0xbd, 0x63, 0x75, 0x78, 0x4a, 0x4e,
+	0x3e, 0x81, 0x6c, 0xa8, 0x84, 0xbe, 0x1b, 0xfa, 0x2e, 0x0d, 0xec, 0xb2, 0x7e, 0x13, 0xa1, 0xdf,
+	0xf2, 0x5f, 0x04, 0x68, 0x15, 0x2c, 0xbd, 0xc2, 0x62, 0x61, 0x57, 0x92, 0x32, 0xfa, 0x2d, 0xff,
+	0x65, 0x2c, 0xd0, 0x8a, 0x62, 0xbd, 0xc1, 0x71, 0x5f, 0xd8, 0x56, 0xba, 0xf4, 0x4c, 0x0e, 0xd1,
+	0x3a, 0xcc, 0x86, 0xbe, 0x3b, 0xc0, 0x47, 0xc9, 0x32, 0xe8, 0x34, 0x43, 0x7f, 0x1f, 0x1f, 0x69,
+	0xc4, 0x06, 0xcc, 0xd1, 0x00, 0x7b, 0x82, 0x9e, 0x10, 0x17, 0x07, 0x2c, 0xb0, 0xab, 0x0a, 0x32,
+	0x9b, 0x4e, 0x3e, 0x0e, 0x58, 0x20, 0x37, 0x6b, 0x42, 0x66, 0xb5, 0x8a, 0x01, 0x30, 0x55, 0x54,
+	0x3d, 0xe6, 0xc6, 0x55, 0x54, 0x45, 0x72, 0x15, 0x05, 0x99, 0x37, 0x55, 0x14, 0x60, 0x1d, 0xaa,
+	0x71, 0x40, 0x4e, 0xa8, 0x27, 0x70, 0xa7, 0x4f, 0xec, 0xab, 0x0a, 0x60, 0x4e, 0xa1, 0x07, 0xb0,
+	0xd2, 0xa3, 0x84, 0x63, 0xee, 0xf5, 0xa8, 0x87, 0xfb, 0xae, 0xfe, 0x90, 0xb9, 0xfa, 0xf8, 0x2d,
+	0x28, 0xfc, 0x0d, 0x13, 0xa0, 0x9d, 0xf0, 0x8d, 0x5c, 0x46, 0xf7, 0x60, 0x6c, 0xc9, 0x8d, 0x4e,
+	0x71, 0x98, 0x30, 0x17, 0x15, 0xf3, 0xba, 0xb9, 0xdc, 0x3e, 0xc5, 0xa1, 0xe6, 0xd5, 0xa0, 0xaa,
+	0x4e, 0x89, 0xab, 0x8d, 0x84, 0x74, 0xda, 0x6a, 0x6a, 0x4f, 0xb9, 0xe9, 0x3f, 0x60, 0x69, 0x80,
+	0xf4, 0xd4, 0x92, 0xf2, 0xcc, 0xec, 0xe8, 0xbc, 0x56, 0x39, 0x90, 0x93, 0xd2, 0x58, 0x15, 0xb5,
+	0xec, 0x44, 0x11, 0xba, 0x07, 0xf3, 0x19, 0x54, 0x7b, 0xec, 0x9a, 0xc2, 0x2f, 0x8c, 0xce, 0x6b,
+	0xb3, 0x29, 0x5e, 0x19, 0x6d, 0x36, 0xe5, 0x28, 0xb7, 0xfd, 0x17, 0x16, 0x35, 0xcf, 0xf4, 0xdc,
+	0x75, 0x95, 0xc9, 0x55, 0xb5, 0xb0, 0x9f, 0x1b, 0x2f, 0xcb, 0x57, 0xdb, 0x6f, 0xd9, 0xc8, 0xf7,
+	0x89, 0xf2, 0xe0, 0xbf, 0x41, 0x73, 0xdc, 0xdc, 0x89, 0x37, 0x14, 0x48, 0xe7, 0xf6, 0x3a, 0xb3,
+	0xe3, 0x46, 0x9a, 0x6d, 0x66, 0x4a, 0x5b, 0xbf, 0x12, 0x35, 0xdb, 0xd2, 0xce, 0xdc, 0x4a, 0xd5,
+	0x72, 0x7f, 0xae, 0xe8, 0x97, 0x9f, 0xa1, 0xa4, 0x49, 0x37, 0x0d, 0x2d, 0xed, 0xc5, 0xd5, 0x31,
+	0x94, 0x76, 0xe3, 0x0e, 0xa0, 0x0c, 0x95, 0xbb, 0xf6, 0xa6, 0xb1, 0xd1, 0x56, 0x6e, 0xdd, 0x06,
+	0x2c, 0x69, 0xf0, 0xb8, 0x81, 0x6f, 0x29, 0xb4, 0xae, 0xd7, 0x0b, 0xd3, 0xc5, 0x59, 0x11, 0x4d,
+	0xf4, 0x6d, 0x43, 0xfb, 0x71, 0x8e, 0xfd, 0x58, 0x5b, 0x95, 0x7c, 0xed, 0x13, 0xda, 0xaa, 0xe8,
+	0x1f, 0x6a, 0x2b, 0x74, 0xed, 0x23, 0x6d, 0x85, 0xdd, 0x49, 0xb1, 0xa6, 0xd9, 0xd7, 0x93, 0xcf,
+	0x9e, 0x5c, 0x38, 0x34, 0x1c, 0xff, 0x65, 0x7a, 0x75, 0xdc, 0x51, 0xdf, 0xfe, 0xad, 0xcb, 0x2e,
+	0xf8, 0xa7, 0x81, 0xe0, 0x67, 0xe9, 0xed, 0x71, 0x1f, 0x4a, 0xd2, 0xe5, 0x76, 0x7d, 0x12, 0xae,
+	0xa2, 0xa0, 0x47, 0xd9, 0x95, 0xb0, 0x31, 0x09, 0x39, 0xbd, 0x39, 0xda, 0x00, 0xfa, 0xc9, 0x15,
+	0x5e, 0x68, 0x6f, 0x4e, 0x20, 0xd1, 0x9c, 0x1b, 0x9d, 0xd7, 0xac, 0xaf, 0x15, 0xf9, 0x60, 0xaf,
+	0xe5, 0x58, 0x5a, 0xe7, 0xc0, 0x0b, 0xeb, 0x04, 0xaa, 0x06, 0x30, 0xbf, 0x77, 0x0b, 0xc6, 0xbd,
+	0x9b, 0x77, 0x04, 0x53, 0x9f, 0xe8, 0x08, 0x8a, 0x9f, 0xec, 0x08, 0x4a, 0x63, 0x1d, 0x41, 0xfd,
+	0xf7, 0x69, 0xb0, 0xb2, 0x86, 0x07, 0x61, 0x58, 0xa5, 0xcc, 0x8d, 0x08, 0x3f, 0xa1, 0x1e, 0x71,
+	0x3b, 0x67, 0x82, 0x44, 0x2e, 0x27, 0x5e, 0xcc, 0x23, 0x7a, 0x42, 0x92, 0x66, 0x71, 0xf3, 0x92,
+	0xce, 0x49, 0xd7, 0xe6, 0x06, 0x65, 0x6d, 0x2d, 0xd3, 0x94, 0x2a, 0x4e, 0x2a, 0x82, 0xbe, 0x83,
+	0xeb, 0x79, 0x88, 0xae, 0xa1, 0x3e, 0x35, 0x81, 0xfa, 0x52, 0xa6, 0xde, 0xcd, 0x95, 0x0f, 0x60,
+	0x89, 0x32, 0xf7, 0x6d, 0x4c, 0xe2, 0x31, 0xdd, 0xe2, 0x04, 0xba, 0x8b, 0x94, 0xbd, 0x52, 0xfc,
+	0x5c, 0xd5, 0x85, 0x15, 0xa3, 0x24, 0xf2, 0x2e, 0x36, 0xb4, 0x4b, 0x13, 0x68, 0x2f, 0x67, 0x39,
+	0xcb, 0xbb, 0x3b, 0x0f, 0xf0, 0x3d, 0x2c, 0x53, 0xe6, 0x9e, 0x62, 0x2a, 0x3e, 0x54, 0x9f, 0x9e,
+	0xac, 0x22, 0xaf, 0x31, 0x15, 0xe3, 0xd2, 0xba, 0x22, 0x03, 0xc2, 0xfd, 0xb1, 0x8a, 0xcc, 0x4c,
+	0x56, 0x91, 0x7d, 0xc5, 0xcf, 0x55, 0x5b, 0xb0, 0x48, 0xd9, 0x87, 0xb9, 0x96, 0x27, 0xd0, 0xbc,
+	0x4a, 0xd9, 0x78, 0x9e, 0xaf, 0x60, 0x31, 0x22, 0x9e, 0x60, 0xdc, 0x74, 0x5b, 0x65, 0x02, 0xc5,
+	0x85, 0x84, 0x9e, 0x49, 0xd6, 0x4f, 0x00, 0xf2, 0x75, 0x34, 0x0f, 0x53, 0x2c, 0x54, 0x47, 0xc7,
+	0x72, 0xa6, 0x58, 0x28, 0x7b, 0xc0, 0xae, 0xfc, 0xec, 0xe8, 0x83, 0x63, 0x39, 0xc9, 0x48, 0x9e,
+	0xa7, 0x01, 0x3e, 0x62, 0x69, 0x13, 0xa8, 0x07, 0x6a, 0x96, 0x06, 0x8c, 0x27, 0x67, 0x47, 0x0f,
+	0xe4, 0xec, 0x09, 0xee, 0xc7, 0x24, 0xed, 0x79, 0xd4, 0xa0, 0xfe, 0x53, 0x01, 0x2a, 0xe9, 0x6f,
+	0x00, 0x7a, 0x64, 0xb6, 0xd1, 0xc5, 0xcf, 0xff, 0x75, 0x48, 0x92, 0xde, 0x4c, 0xd6, 0x6b, 0xdf,
+	0xcf, 0x7b, 0xed, 0x7f, 0x4c, 0x4e, 0x1a, 0x72, 0x02, 0x56, 0x36, 0x67, 0xec, 0xb6, 0x30, 0xb6,
+	0xdb, 0x1a, 0x54, 0x7b, 0x1e, 0x76, 0x7b, 0x38, 0xe8, 0xf6, 0x89, 0xee, 0x10, 0xe7, 0x1c, 0xe8,
+	0x79, 0xf8, 0xb9, 0x9e, 0x49, 0x01, 0xac, 0x73, 0x44, 0x3c, 0x11, 0xa9, 0xa2, 0x68, 0xc0, 0x4b,
+	0x3d, 0x53, 0xff, 0x65, 0x0a, 0xaa, 0xc6, 0x9f, 0x8b, 0xec, 0xa1, 0x03, 0x3c, 0x48, 0xe3, 0xa8,
+	0x67, 0xd9, 0xb1, 0xf1, 0xa1, 0xfe, 0x96, 0x24, 0x9f, 0xa9, 0x32, 0x1f, 0xaa, 0x8f, 0x02, 0xba,
+	0x0d, 0xc0, 0x87, 0x6e, 0x88, 0xbd, 0x63, 0x92, 0xc8, 0x97, 0x1c, 0x8b, 0x0f, 0x5b, 0x7a, 0x02,
+	0xdd, 0x04, 0x8b, 0x0f, 0x5d, 0xc2, 0x39, 0xe3, 0x51, 0x52, 0xfb, 0x0a, 0x1f, 0x3e, 0x55, 0xe3,
+	0x84, 0xdb, 0xe5, 0x4c, 0xf6, 0x02, 0xc9, 0x3b, 0xb0, 0xf8, 0xf0, 0x89, 0x9e, 0x90, 0x51, 0x45,
+	0x1a, 0x55, 0xb7, 0x9e, 0x65, 0x91, 0x47, 0x15, 0x79, 0x54, 0xdd, 0x7a, 0x5a, 0xc2, 0x8c, 0x2a,
+	0xb2, 0xa8, 0xba, 0xfb, 0xac, 0x08, 0x23, 0xaa, 0xc8, 0xa3, 0x5a, 0x29, 0x37, 0x89, 0xda, 0xb4,
+	0xdf, 0xbd, 0x5f, 0xbb, 0xf2, 0xc7, 0xfb, 0xb5, 0x2b, 0x3f, 0x8e, 0xd6, 0x0a, 0xef, 0x46, 0x6b,
+	0x85, 0xdf, 0x46, 0x6b, 0x85, 0xbf, 0x46, 0x6b, 0x85, 0xce, 0x8c, 0xfa, 0x0d, 0xff, 0xff, 0xdf,
+	0x01, 0x00, 0x00, 0xff, 0xff, 0x19, 0x9d, 0xe2, 0xd3, 0xe5, 0x0f, 0x00, 0x00,
 }
 }

+ 13 - 0
vendor/github.com/containerd/cgroups/metrics.proto

@@ -11,6 +11,7 @@ message Metrics {
 	MemoryStat memory = 4;
 	MemoryStat memory = 4;
 	BlkIOStat blkio = 5;
 	BlkIOStat blkio = 5;
 	RdmaStat rdma = 6;
 	RdmaStat rdma = 6;
+	repeated NetworkStat network = 7;
 }
 }
 
 
 message HugetlbStat {
 message HugetlbStat {
@@ -121,3 +122,15 @@ message RdmaEntry {
 	uint32 hca_handles = 2;
 	uint32 hca_handles = 2;
 	uint32 hca_objects = 3;
 	uint32 hca_objects = 3;
 }
 }
+
+message NetworkStat {
+	string name = 1;
+	uint64 rx_bytes = 2;
+	uint64 rx_packets = 3;
+	uint64 rx_errors  = 4;
+	uint64 rx_dropped = 5;
+	uint64 tx_bytes = 6;
+	uint64 tx_packets = 7;
+	uint64 tx_errors = 8;
+	uint64 tx_dropped = 9;
+}

+ 1 - 1
vendor/github.com/containerd/cgroups/utils.go

@@ -168,7 +168,7 @@ func readTasksPids(path string, subsystem Name) ([]Task, error) {
 func hugePageSizes() ([]string, error) {
 func hugePageSizes() ([]string, error) {
 	var (
 	var (
 		pageSizes []string
 		pageSizes []string
-		sizeList  = []string{"B", "kB", "MB", "GB", "TB", "PB"}
+		sizeList  = []string{"B", "KB", "MB", "GB", "TB", "PB"}
 	)
 	)
 	files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages")
 	files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages")
 	if err != nil {
 	if err != nil {

+ 1 - 1
vendor/github.com/containerd/containerd/README.md

@@ -218,7 +218,7 @@ This will be the best place to discuss design and implementation.
 For sync communication we have a community slack with a #containerd channel that everyone is welcome to join and chat about development.
 For sync communication we have a community slack with a #containerd channel that everyone is welcome to join and chat about development.
 
 
 **Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com.
 **Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com.
-[Click here for an invite to docker community slack.](https://join.slack.com/t/dockercommunity/shared_invite/enQtNDY4MDc1Mzc0MzIwLTgxZDBlMmM4ZGEyNDc1N2FkMzlhODJkYmE1YTVkYjM1MDE3ZjAwZjBkOGFlOTJkZjRmZGYzNjYyY2M3ZTUxYzQ)
+[Click here for an invite to docker community slack.](https://dockr.ly/slack)
 
 
 ### Security audit
 ### Security audit
 
 

+ 227 - 39
vendor/github.com/containerd/containerd/api/services/diff/v1/diff.pb.go

@@ -9,6 +9,7 @@ import (
 	types "github.com/containerd/containerd/api/types"
 	types "github.com/containerd/containerd/api/types"
 	proto "github.com/gogo/protobuf/proto"
 	proto "github.com/gogo/protobuf/proto"
 	github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
 	github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
+	types1 "github.com/gogo/protobuf/types"
 	grpc "google.golang.org/grpc"
 	grpc "google.golang.org/grpc"
 	io "io"
 	io "io"
 	math "math"
 	math "math"
@@ -29,11 +30,12 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
 
 type ApplyRequest struct {
 type ApplyRequest struct {
 	// Diff is the descriptor of the diff to be extracted
 	// Diff is the descriptor of the diff to be extracted
-	Diff                 *types.Descriptor `protobuf:"bytes,1,opt,name=diff,proto3" json:"diff,omitempty"`
-	Mounts               []*types.Mount    `protobuf:"bytes,2,rep,name=mounts,proto3" json:"mounts,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}          `json:"-"`
-	XXX_unrecognized     []byte            `json:"-"`
-	XXX_sizecache        int32             `json:"-"`
+	Diff                 *types.Descriptor      `protobuf:"bytes,1,opt,name=diff,proto3" json:"diff,omitempty"`
+	Mounts               []*types.Mount         `protobuf:"bytes,2,rep,name=mounts,proto3" json:"mounts,omitempty"`
+	Payloads             map[string]*types1.Any `protobuf:"bytes,3,rep,name=payloads,proto3" json:"payloads,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	XXX_NoUnkeyedLiteral struct{}               `json:"-"`
+	XXX_unrecognized     []byte                 `json:"-"`
+	XXX_sizecache        int32                  `json:"-"`
 }
 }
 
 
 func (m *ApplyRequest) Reset()      { *m = ApplyRequest{} }
 func (m *ApplyRequest) Reset()      { *m = ApplyRequest{} }
@@ -205,6 +207,7 @@ var xxx_messageInfo_DiffResponse proto.InternalMessageInfo
 
 
 func init() {
 func init() {
 	proto.RegisterType((*ApplyRequest)(nil), "containerd.services.diff.v1.ApplyRequest")
 	proto.RegisterType((*ApplyRequest)(nil), "containerd.services.diff.v1.ApplyRequest")
+	proto.RegisterMapType((map[string]*types1.Any)(nil), "containerd.services.diff.v1.ApplyRequest.PayloadsEntry")
 	proto.RegisterType((*ApplyResponse)(nil), "containerd.services.diff.v1.ApplyResponse")
 	proto.RegisterType((*ApplyResponse)(nil), "containerd.services.diff.v1.ApplyResponse")
 	proto.RegisterType((*DiffRequest)(nil), "containerd.services.diff.v1.DiffRequest")
 	proto.RegisterType((*DiffRequest)(nil), "containerd.services.diff.v1.DiffRequest")
 	proto.RegisterMapType((map[string]string)(nil), "containerd.services.diff.v1.DiffRequest.LabelsEntry")
 	proto.RegisterMapType((map[string]string)(nil), "containerd.services.diff.v1.DiffRequest.LabelsEntry")
@@ -216,36 +219,40 @@ func init() {
 }
 }
 
 
 var fileDescriptor_3b36a99e6faaa935 = []byte{
 var fileDescriptor_3b36a99e6faaa935 = []byte{
-	// 457 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4f, 0x6f, 0xd3, 0x30,
-	0x14, 0xaf, 0xfb, 0x0f, 0xf5, 0x75, 0x48, 0xc8, 0x9a, 0x44, 0x14, 0x20, 0xaa, 0x7a, 0xea, 0x40,
-	0x38, 0xac, 0xa0, 0x09, 0xb6, 0xcb, 0x40, 0x43, 0x5c, 0xc6, 0x25, 0xda, 0x01, 0x81, 0x04, 0x4a,
-	0x9b, 0x97, 0xce, 0x22, 0x8d, 0xbd, 0xd8, 0xad, 0x94, 0x1b, 0xdf, 0x85, 0x8f, 0xc2, 0x65, 0x47,
-	0x8e, 0x1c, 0x69, 0x3f, 0x09, 0xb2, 0x93, 0x40, 0x24, 0xa4, 0x12, 0x76, 0xca, 0xcb, 0xf3, 0xef,
-	0x9f, 0xfd, 0x6c, 0x38, 0x5d, 0x70, 0x7d, 0xb9, 0x9a, 0xb1, 0xb9, 0x58, 0xfa, 0x73, 0x91, 0xea,
-	0x90, 0xa7, 0x98, 0x45, 0xf5, 0x32, 0x94, 0xdc, 0x57, 0x98, 0xad, 0xf9, 0x1c, 0x95, 0x1f, 0xf1,
-	0x38, 0xf6, 0xd7, 0x87, 0xf6, 0xcb, 0x64, 0x26, 0xb4, 0xa0, 0xf7, 0xfe, 0x60, 0x59, 0x85, 0x63,
-	0x76, 0x7d, 0x7d, 0xe8, 0xee, 0x2f, 0xc4, 0x42, 0x58, 0x9c, 0x6f, 0xaa, 0x82, 0xe2, 0x1e, 0x35,
-	0x32, 0xd5, 0xb9, 0x44, 0xe5, 0x2f, 0xc5, 0x2a, 0xd5, 0x25, 0xef, 0xe4, 0x3f, 0x78, 0x11, 0xaa,
-	0x79, 0xc6, 0xa5, 0x16, 0x59, 0x41, 0x1e, 0x5f, 0xc1, 0xde, 0x4b, 0x29, 0x93, 0x3c, 0xc0, 0xab,
-	0x15, 0x2a, 0x4d, 0x9f, 0x40, 0xd7, 0xa4, 0x74, 0xc8, 0x88, 0x4c, 0x86, 0xd3, 0xfb, 0xac, 0xb6,
-	0x0d, 0xab, 0xc0, 0xce, 0x7e, 0x2b, 0x04, 0x16, 0x49, 0x7d, 0xe8, 0xdb, 0x34, 0xca, 0x69, 0x8f,
-	0x3a, 0x93, 0xe1, 0xf4, 0xee, 0xdf, 0x9c, 0xb7, 0x66, 0x3d, 0x28, 0x61, 0xe3, 0x37, 0x70, 0xbb,
-	0xb4, 0x54, 0x52, 0xa4, 0x0a, 0xe9, 0x11, 0xdc, 0x0a, 0xa5, 0x4c, 0x38, 0x46, 0x8d, 0x6c, 0x2b,
-	0xf0, 0xf8, 0x6b, 0x1b, 0x86, 0x67, 0x3c, 0x8e, 0xab, 0xec, 0x8f, 0xa0, 0x9b, 0x60, 0xac, 0x1d,
-	0xb2, 0x3b, 0x87, 0x05, 0xd1, 0xc7, 0xd0, 0xcb, 0xf8, 0xe2, 0x52, 0xff, 0x2b, 0x75, 0x81, 0xa2,
-	0x0f, 0x00, 0x96, 0x18, 0xf1, 0xf0, 0x93, 0x59, 0x73, 0x3a, 0x23, 0x32, 0x19, 0x04, 0x03, 0xdb,
-	0xb9, 0xc8, 0x25, 0xd2, 0x3b, 0xd0, 0xc9, 0x30, 0x76, 0xba, 0xb6, 0x6f, 0x4a, 0x7a, 0x0e, 0xfd,
-	0x24, 0x9c, 0x61, 0xa2, 0x9c, 0x9e, 0x35, 0x78, 0xc6, 0x76, 0xdc, 0x08, 0x56, 0xdb, 0x06, 0x3b,
-	0xb7, 0xb4, 0xd7, 0xa9, 0xce, 0xf2, 0xa0, 0xd4, 0x70, 0x5f, 0xc0, 0xb0, 0xd6, 0x36, 0x76, 0x9f,
-	0x31, 0xb7, 0xa7, 0x35, 0x08, 0x4c, 0x49, 0xf7, 0xa1, 0xb7, 0x0e, 0x93, 0x15, 0x3a, 0x6d, 0xdb,
-	0x2b, 0x7e, 0x8e, 0xdb, 0xcf, 0xc9, 0xf8, 0x14, 0xf6, 0x0a, 0xf5, 0xf2, 0xb4, 0xab, 0x09, 0x77,
-	0x9a, 0x4e, 0x78, 0xfa, 0x8d, 0x40, 0xd7, 0x48, 0xd0, 0x8f, 0xd0, 0xb3, 0x93, 0xa3, 0x07, 0x3b,
-	0x37, 0x53, 0xbf, 0x50, 0xee, 0xc3, 0x26, 0xd0, 0x32, 0xda, 0x87, 0xd2, 0x67, 0xd2, 0xf4, 0xac,
-	0xdc, 0x83, 0x06, 0xc8, 0x42, 0xfc, 0xd5, 0xc5, 0xf5, 0xc6, 0x6b, 0xfd, 0xd8, 0x78, 0xad, 0x2f,
-	0x5b, 0x8f, 0x5c, 0x6f, 0x3d, 0xf2, 0x7d, 0xeb, 0x91, 0x9f, 0x5b, 0x8f, 0xbc, 0x3f, 0xbe, 0xd1,
-	0x6b, 0x3f, 0x31, 0xdf, 0x77, 0xad, 0x59, 0xdf, 0x3e, 0xa4, 0xa7, 0xbf, 0x02, 0x00, 0x00, 0xff,
-	0xff, 0x61, 0xd1, 0x6e, 0x9e, 0x34, 0x04, 0x00, 0x00,
+	// 526 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xd3, 0x4c,
+	0x10, 0x8d, 0xed, 0x24, 0xdf, 0x97, 0x49, 0x2b, 0xa1, 0x55, 0x24, 0x8c, 0x01, 0xab, 0xca, 0x29,
+	0x2d, 0x62, 0x4d, 0x03, 0x2a, 0xd0, 0x5e, 0x5a, 0x54, 0xc4, 0xa5, 0x48, 0x60, 0x7a, 0x40, 0x20,
+	0x81, 0x9c, 0x78, 0xed, 0xae, 0x70, 0xbc, 0x8b, 0x77, 0x1d, 0xc9, 0x37, 0xfe, 0x06, 0x67, 0x7e,
+	0x0a, 0x97, 0x1e, 0x39, 0x72, 0xa4, 0xf9, 0x25, 0xc8, 0xeb, 0x75, 0x31, 0x02, 0x05, 0xc3, 0xc9,
+	0x9b, 0x9d, 0xf7, 0xde, 0xce, 0xbc, 0x37, 0x0a, 0x1c, 0xc6, 0x54, 0x9e, 0xe5, 0x33, 0x3c, 0x67,
+	0x0b, 0x6f, 0xce, 0x52, 0x19, 0xd0, 0x94, 0x64, 0x61, 0xf3, 0x18, 0x70, 0xea, 0x09, 0x92, 0x2d,
+	0xe9, 0x9c, 0x08, 0x2f, 0xa4, 0x51, 0xe4, 0x2d, 0x77, 0xd5, 0x17, 0xf3, 0x8c, 0x49, 0x86, 0xae,
+	0xff, 0xc0, 0xe2, 0x1a, 0x87, 0x55, 0x7d, 0xb9, 0xeb, 0x8c, 0x62, 0x16, 0x33, 0x85, 0xf3, 0xca,
+	0x53, 0x45, 0x71, 0xae, 0xc5, 0x8c, 0xc5, 0x09, 0xf1, 0xd4, 0xaf, 0x59, 0x1e, 0x79, 0x41, 0x5a,
+	0xe8, 0xd2, 0x5e, 0xab, 0x7e, 0x64, 0xc1, 0x89, 0xf0, 0x16, 0x2c, 0x4f, 0xa5, 0xe6, 0x1d, 0xfc,
+	0x05, 0x2f, 0x24, 0x62, 0x9e, 0x51, 0x2e, 0x59, 0x56, 0x91, 0xc7, 0x1f, 0x4d, 0xd8, 0x38, 0xe2,
+	0x3c, 0x29, 0x7c, 0xf2, 0x3e, 0x27, 0x42, 0xa2, 0x3b, 0xd0, 0x2d, 0x27, 0xb0, 0x8d, 0x2d, 0x63,
+	0x32, 0x9c, 0xde, 0xc0, 0x8d, 0x11, 0x95, 0x04, 0x3e, 0xbe, 0x94, 0xf0, 0x15, 0x12, 0x79, 0xd0,
+	0x57, 0xed, 0x08, 0xdb, 0xdc, 0xb2, 0x26, 0xc3, 0xe9, 0xd5, 0x5f, 0x39, 0x4f, 0xcb, 0xba, 0xaf,
+	0x61, 0xe8, 0x05, 0xfc, 0xcf, 0x83, 0x22, 0x61, 0x41, 0x28, 0x6c, 0x4b, 0x51, 0xee, 0xe3, 0x35,
+	0x4e, 0xe2, 0x66, 0x7f, 0xf8, 0x99, 0x66, 0x3e, 0x4e, 0x65, 0x56, 0xf8, 0x97, 0x42, 0xce, 0x73,
+	0xd8, 0xfc, 0xa9, 0x84, 0xae, 0x80, 0xf5, 0x8e, 0x14, 0x6a, 0x8e, 0x81, 0x5f, 0x1e, 0xd1, 0x0e,
+	0xf4, 0x96, 0x41, 0x92, 0x13, 0xdb, 0x54, 0xb3, 0x8d, 0x70, 0x95, 0x05, 0xae, 0xb3, 0xc0, 0x47,
+	0x69, 0xe1, 0x57, 0x90, 0x7d, 0xf3, 0x81, 0x31, 0x7e, 0x02, 0x9b, 0xfa, 0x69, 0xc1, 0x59, 0x2a,
+	0x08, 0xda, 0x83, 0xff, 0x02, 0xce, 0x13, 0x4a, 0xc2, 0x56, 0xf6, 0xd4, 0xe0, 0xf1, 0x27, 0x13,
+	0x86, 0xc7, 0x34, 0x8a, 0x6a, 0x8f, 0x6f, 0x41, 0x37, 0x21, 0x91, 0xb4, 0x8d, 0xf5, 0x7e, 0x29,
+	0x10, 0xba, 0x0d, 0xbd, 0x8c, 0xc6, 0x67, 0xf2, 0x4f, 0xee, 0x56, 0x28, 0x74, 0x13, 0x60, 0x41,
+	0x42, 0x1a, 0xbc, 0x2d, 0x6b, 0xb6, 0xa5, 0xa6, 0x1f, 0xa8, 0x9b, 0xd3, 0x82, 0x93, 0xd2, 0x95,
+	0x8c, 0x44, 0x76, 0xb7, 0x72, 0x25, 0x23, 0x11, 0x3a, 0x81, 0x7e, 0x12, 0xcc, 0x48, 0x22, 0xec,
+	0x9e, 0x7a, 0xe0, 0xde, 0xda, 0x2c, 0x1a, 0x63, 0xe0, 0x13, 0x45, 0xab, 0x82, 0xd0, 0x1a, 0xce,
+	0x43, 0x18, 0x36, 0xae, 0x7f, 0x13, 0xc2, 0xa8, 0x19, 0xc2, 0xa0, 0x69, 0xf7, 0x21, 0x6c, 0x54,
+	0xea, 0xda, 0xed, 0x7a, 0x13, 0xad, 0xb6, 0x9b, 0x38, 0xfd, 0x6c, 0x40, 0xb7, 0x94, 0x40, 0x6f,
+	0xa0, 0xa7, 0x92, 0x43, 0xdb, 0xad, 0x17, 0xcb, 0xd9, 0x69, 0x03, 0xd5, 0xad, 0xbd, 0xd6, 0xef,
+	0x4c, 0xda, 0x7a, 0xe5, 0x6c, 0xb7, 0x40, 0x56, 0xe2, 0x8f, 0x4e, 0xcf, 0x2f, 0xdc, 0xce, 0xd7,
+	0x0b, 0xb7, 0xf3, 0x61, 0xe5, 0x1a, 0xe7, 0x2b, 0xd7, 0xf8, 0xb2, 0x72, 0x8d, 0x6f, 0x2b, 0xd7,
+	0x78, 0xb5, 0xff, 0x4f, 0xff, 0x58, 0x07, 0xe5, 0xf7, 0x65, 0x67, 0xd6, 0x57, 0x7b, 0x7e, 0xf7,
+	0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x85, 0x25, 0xb8, 0xf8, 0x04, 0x00, 0x00,
 }
 }
 
 
 // Reference imports to suppress errors if they are not otherwise used.
 // Reference imports to suppress errors if they are not otherwise used.
@@ -400,6 +407,34 @@ func (m *ApplyRequest) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 			i += n
 		}
 		}
 	}
 	}
+	if len(m.Payloads) > 0 {
+		for k, _ := range m.Payloads {
+			dAtA[i] = 0x1a
+			i++
+			v := m.Payloads[k]
+			msgSize := 0
+			if v != nil {
+				msgSize = v.Size()
+				msgSize += 1 + sovDiff(uint64(msgSize))
+			}
+			mapSize := 1 + len(k) + sovDiff(uint64(len(k))) + msgSize
+			i = encodeVarintDiff(dAtA, i, uint64(mapSize))
+			dAtA[i] = 0xa
+			i++
+			i = encodeVarintDiff(dAtA, i, uint64(len(k)))
+			i += copy(dAtA[i:], k)
+			if v != nil {
+				dAtA[i] = 0x12
+				i++
+				i = encodeVarintDiff(dAtA, i, uint64(v.Size()))
+				n2, err := v.MarshalTo(dAtA[i:])
+				if err != nil {
+					return 0, err
+				}
+				i += n2
+			}
+		}
+	}
 	if m.XXX_unrecognized != nil {
 	if m.XXX_unrecognized != nil {
 		i += copy(dAtA[i:], m.XXX_unrecognized)
 		i += copy(dAtA[i:], m.XXX_unrecognized)
 	}
 	}
@@ -425,11 +460,11 @@ func (m *ApplyResponse) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0xa
 		dAtA[i] = 0xa
 		i++
 		i++
 		i = encodeVarintDiff(dAtA, i, uint64(m.Applied.Size()))
 		i = encodeVarintDiff(dAtA, i, uint64(m.Applied.Size()))
-		n2, err := m.Applied.MarshalTo(dAtA[i:])
+		n3, err := m.Applied.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n2
+		i += n3
 	}
 	}
 	if m.XXX_unrecognized != nil {
 	if m.XXX_unrecognized != nil {
 		i += copy(dAtA[i:], m.XXX_unrecognized)
 		i += copy(dAtA[i:], m.XXX_unrecognized)
@@ -530,11 +565,11 @@ func (m *DiffResponse) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x1a
 		dAtA[i] = 0x1a
 		i++
 		i++
 		i = encodeVarintDiff(dAtA, i, uint64(m.Diff.Size()))
 		i = encodeVarintDiff(dAtA, i, uint64(m.Diff.Size()))
-		n3, err := m.Diff.MarshalTo(dAtA[i:])
+		n4, err := m.Diff.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n3
+		i += n4
 	}
 	}
 	if m.XXX_unrecognized != nil {
 	if m.XXX_unrecognized != nil {
 		i += copy(dAtA[i:], m.XXX_unrecognized)
 		i += copy(dAtA[i:], m.XXX_unrecognized)
@@ -567,6 +602,19 @@ func (m *ApplyRequest) Size() (n int) {
 			n += 1 + l + sovDiff(uint64(l))
 			n += 1 + l + sovDiff(uint64(l))
 		}
 		}
 	}
 	}
+	if len(m.Payloads) > 0 {
+		for k, v := range m.Payloads {
+			_ = k
+			_ = v
+			l = 0
+			if v != nil {
+				l = v.Size()
+				l += 1 + sovDiff(uint64(l))
+			}
+			mapEntrySize := 1 + len(k) + sovDiff(uint64(len(k))) + l
+			n += mapEntrySize + 1 + sovDiff(uint64(mapEntrySize))
+		}
+	}
 	if m.XXX_unrecognized != nil {
 	if m.XXX_unrecognized != nil {
 		n += len(m.XXX_unrecognized)
 		n += len(m.XXX_unrecognized)
 	}
 	}
@@ -662,9 +710,20 @@ func (this *ApplyRequest) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
+	keysForPayloads := make([]string, 0, len(this.Payloads))
+	for k, _ := range this.Payloads {
+		keysForPayloads = append(keysForPayloads, k)
+	}
+	github_com_gogo_protobuf_sortkeys.Strings(keysForPayloads)
+	mapStringForPayloads := "map[string]*types1.Any{"
+	for _, k := range keysForPayloads {
+		mapStringForPayloads += fmt.Sprintf("%v: %v,", k, this.Payloads[k])
+	}
+	mapStringForPayloads += "}"
 	s := strings.Join([]string{`&ApplyRequest{`,
 	s := strings.Join([]string{`&ApplyRequest{`,
 		`Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "types.Descriptor", 1) + `,`,
 		`Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "types.Descriptor", 1) + `,`,
 		`Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "types.Mount", 1) + `,`,
 		`Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "types.Mount", 1) + `,`,
+		`Payloads:` + mapStringForPayloads + `,`,
 		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
 		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
@@ -824,6 +883,135 @@ func (m *ApplyRequest) Unmarshal(dAtA []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Payloads", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowDiff
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthDiff
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthDiff
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Payloads == nil {
+				m.Payloads = make(map[string]*types1.Any)
+			}
+			var mapkey string
+			var mapvalue *types1.Any
+			for iNdEx < postIndex {
+				entryPreIndex := iNdEx
+				var wire uint64
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return ErrIntOverflowDiff
+					}
+					if iNdEx >= l {
+						return io.ErrUnexpectedEOF
+					}
+					b := dAtA[iNdEx]
+					iNdEx++
+					wire |= uint64(b&0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				fieldNum := int32(wire >> 3)
+				if fieldNum == 1 {
+					var stringLenmapkey uint64
+					for shift := uint(0); ; shift += 7 {
+						if shift >= 64 {
+							return ErrIntOverflowDiff
+						}
+						if iNdEx >= l {
+							return io.ErrUnexpectedEOF
+						}
+						b := dAtA[iNdEx]
+						iNdEx++
+						stringLenmapkey |= uint64(b&0x7F) << shift
+						if b < 0x80 {
+							break
+						}
+					}
+					intStringLenmapkey := int(stringLenmapkey)
+					if intStringLenmapkey < 0 {
+						return ErrInvalidLengthDiff
+					}
+					postStringIndexmapkey := iNdEx + intStringLenmapkey
+					if postStringIndexmapkey < 0 {
+						return ErrInvalidLengthDiff
+					}
+					if postStringIndexmapkey > l {
+						return io.ErrUnexpectedEOF
+					}
+					mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
+					iNdEx = postStringIndexmapkey
+				} else if fieldNum == 2 {
+					var mapmsglen int
+					for shift := uint(0); ; shift += 7 {
+						if shift >= 64 {
+							return ErrIntOverflowDiff
+						}
+						if iNdEx >= l {
+							return io.ErrUnexpectedEOF
+						}
+						b := dAtA[iNdEx]
+						iNdEx++
+						mapmsglen |= int(b&0x7F) << shift
+						if b < 0x80 {
+							break
+						}
+					}
+					if mapmsglen < 0 {
+						return ErrInvalidLengthDiff
+					}
+					postmsgIndex := iNdEx + mapmsglen
+					if postmsgIndex < 0 {
+						return ErrInvalidLengthDiff
+					}
+					if postmsgIndex > l {
+						return io.ErrUnexpectedEOF
+					}
+					mapvalue = &types1.Any{}
+					if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil {
+						return err
+					}
+					iNdEx = postmsgIndex
+				} else {
+					iNdEx = entryPreIndex
+					skippy, err := skipDiff(dAtA[iNdEx:])
+					if err != nil {
+						return err
+					}
+					if skippy < 0 {
+						return ErrInvalidLengthDiff
+					}
+					if (iNdEx + skippy) > postIndex {
+						return io.ErrUnexpectedEOF
+					}
+					iNdEx += skippy
+				}
+			}
+			m.Payloads[mapkey] = mapvalue
+			iNdEx = postIndex
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipDiff(dAtA[iNdEx:])
 			skippy, err := skipDiff(dAtA[iNdEx:])

+ 3 - 0
vendor/github.com/containerd/containerd/api/services/diff/v1/diff.proto

@@ -3,6 +3,7 @@ syntax = "proto3";
 package containerd.services.diff.v1;
 package containerd.services.diff.v1;
 
 
 import weak "gogoproto/gogo.proto";
 import weak "gogoproto/gogo.proto";
+import "google/protobuf/any.proto";
 import "github.com/containerd/containerd/api/types/mount.proto";
 import "github.com/containerd/containerd/api/types/mount.proto";
 import "github.com/containerd/containerd/api/types/descriptor.proto";
 import "github.com/containerd/containerd/api/types/descriptor.proto";
 
 
@@ -25,6 +26,8 @@ message ApplyRequest {
 	containerd.types.Descriptor diff = 1;
 	containerd.types.Descriptor diff = 1;
 
 
 	repeated containerd.types.Mount mounts = 2;
 	repeated containerd.types.Mount mounts = 2;
+
+	map<string, google.protobuf.Any> payloads = 3;
 }
 }
 
 
 message ApplyResponse {
 message ApplyResponse {

+ 252 - 32
vendor/github.com/containerd/containerd/api/services/introspection/v1/introspection.pb.go

@@ -10,6 +10,7 @@ import (
 	rpc "github.com/gogo/googleapis/google/rpc"
 	rpc "github.com/gogo/googleapis/google/rpc"
 	proto "github.com/gogo/protobuf/proto"
 	proto "github.com/gogo/protobuf/proto"
 	github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
 	github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
+	types1 "github.com/gogo/protobuf/types"
 	grpc "google.golang.org/grpc"
 	grpc "google.golang.org/grpc"
 	io "io"
 	io "io"
 	math "math"
 	math "math"
@@ -191,11 +192,51 @@ func (m *PluginsResponse) XXX_DiscardUnknown() {
 
 
 var xxx_messageInfo_PluginsResponse proto.InternalMessageInfo
 var xxx_messageInfo_PluginsResponse proto.InternalMessageInfo
 
 
+type ServerResponse struct {
+	UUID                 string   `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *ServerResponse) Reset()      { *m = ServerResponse{} }
+func (*ServerResponse) ProtoMessage() {}
+func (*ServerResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_1a14fda866f10715, []int{3}
+}
+func (m *ServerResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ServerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ServerResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *ServerResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ServerResponse.Merge(m, src)
+}
+func (m *ServerResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *ServerResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_ServerResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ServerResponse proto.InternalMessageInfo
+
 func init() {
 func init() {
 	proto.RegisterType((*Plugin)(nil), "containerd.services.introspection.v1.Plugin")
 	proto.RegisterType((*Plugin)(nil), "containerd.services.introspection.v1.Plugin")
 	proto.RegisterMapType((map[string]string)(nil), "containerd.services.introspection.v1.Plugin.ExportsEntry")
 	proto.RegisterMapType((map[string]string)(nil), "containerd.services.introspection.v1.Plugin.ExportsEntry")
 	proto.RegisterType((*PluginsRequest)(nil), "containerd.services.introspection.v1.PluginsRequest")
 	proto.RegisterType((*PluginsRequest)(nil), "containerd.services.introspection.v1.PluginsRequest")
 	proto.RegisterType((*PluginsResponse)(nil), "containerd.services.introspection.v1.PluginsResponse")
 	proto.RegisterType((*PluginsResponse)(nil), "containerd.services.introspection.v1.PluginsResponse")
+	proto.RegisterType((*ServerResponse)(nil), "containerd.services.introspection.v1.ServerResponse")
 }
 }
 
 
 func init() {
 func init() {
@@ -203,38 +244,42 @@ func init() {
 }
 }
 
 
 var fileDescriptor_1a14fda866f10715 = []byte{
 var fileDescriptor_1a14fda866f10715 = []byte{
-	// 487 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
-	0x10, 0xcd, 0x3a, 0x69, 0xdc, 0x4c, 0xca, 0x87, 0x56, 0x15, 0x58, 0x3e, 0xb8, 0x51, 0xc4, 0x21,
-	0x42, 0xb0, 0x56, 0x03, 0x48, 0xb4, 0x48, 0x1c, 0x22, 0x72, 0xa8, 0xd4, 0x43, 0xe5, 0x5e, 0x10,
-	0x97, 0xca, 0x71, 0x36, 0x66, 0x85, 0xeb, 0xdd, 0xee, 0xae, 0x2d, 0x72, 0xe3, 0xc6, 0x5f, 0xcb,
-	0x91, 0x23, 0xa7, 0x8a, 0xfa, 0x37, 0xf0, 0x03, 0x90, 0xbd, 0x76, 0x9b, 0xdc, 0x12, 0x71, 0x9b,
-	0x79, 0x7e, 0x6f, 0xe6, 0xcd, 0x93, 0x17, 0x82, 0x98, 0xe9, 0xaf, 0xd9, 0x8c, 0x44, 0xfc, 0xda,
-	0x8f, 0x78, 0xaa, 0x43, 0x96, 0x52, 0x39, 0x5f, 0x2f, 0x43, 0xc1, 0x7c, 0x45, 0x65, 0xce, 0x22,
-	0xaa, 0x7c, 0x96, 0x6a, 0xc9, 0x95, 0xa0, 0x91, 0x66, 0x3c, 0xf5, 0xf3, 0xe3, 0x4d, 0x80, 0x08,
-	0xc9, 0x35, 0xc7, 0x2f, 0x1e, 0xd4, 0xa4, 0x51, 0x92, 0x4d, 0x62, 0x7e, 0xec, 0x9e, 0x6c, 0xb5,
-	0x59, 0x2f, 0x05, 0x55, 0xbe, 0x48, 0x42, 0xbd, 0xe0, 0xf2, 0xda, 0x2c, 0x70, 0x9f, 0xc7, 0x9c,
-	0xc7, 0x09, 0xf5, 0xa5, 0x88, 0x7c, 0xa5, 0x43, 0x9d, 0xa9, 0xfa, 0xc3, 0x61, 0xcc, 0x63, 0x5e,
-	0x95, 0x7e, 0x59, 0x19, 0x74, 0xf8, 0xd7, 0x82, 0xee, 0x45, 0x92, 0xc5, 0x2c, 0xc5, 0x18, 0x3a,
-	0xe5, 0x44, 0x07, 0x0d, 0xd0, 0xa8, 0x17, 0x54, 0x35, 0x7e, 0x06, 0x16, 0x9b, 0x3b, 0x56, 0x89,
-	0x4c, 0xba, 0xc5, 0xed, 0x91, 0x75, 0xf6, 0x29, 0xb0, 0xd8, 0x1c, 0xbb, 0xb0, 0x2f, 0xe9, 0x4d,
-	0xc6, 0x24, 0x55, 0x4e, 0x7b, 0xd0, 0x1e, 0xf5, 0x82, 0xfb, 0x1e, 0x7f, 0x84, 0x5e, 0xe3, 0x49,
-	0x39, 0x9d, 0x41, 0x7b, 0xd4, 0x1f, 0xbb, 0x64, 0xed, 0xec, 0xca, 0x36, 0xb9, 0xa8, 0x29, 0x93,
-	0xce, 0xea, 0xf6, 0xa8, 0x15, 0x3c, 0x48, 0xf0, 0x25, 0xd8, 0xf4, 0xbb, 0xe0, 0x52, 0x2b, 0x67,
-	0xaf, 0x52, 0x9f, 0x90, 0x6d, 0x42, 0x23, 0xe6, 0x0c, 0x32, 0x35, 0xda, 0x69, 0xaa, 0xe5, 0x32,
-	0x68, 0x26, 0xe1, 0x21, 0x1c, 0x44, 0xa1, 0x08, 0x67, 0x2c, 0x61, 0x9a, 0x51, 0xe5, 0x74, 0x2b,
-	0xd3, 0x1b, 0x18, 0x7e, 0x0d, 0xfb, 0x2c, 0x65, 0xfa, 0x8a, 0x4a, 0xe9, 0xd8, 0x03, 0x34, 0xea,
-	0x8f, 0x31, 0x31, 0x69, 0x12, 0x29, 0x22, 0x72, 0x59, 0xa5, 0x19, 0xd8, 0x25, 0x67, 0x2a, 0xa5,
-	0x7b, 0x0a, 0x07, 0xeb, 0xbb, 0xf0, 0x53, 0x68, 0x7f, 0xa3, 0xcb, 0x3a, 0xbe, 0xb2, 0xc4, 0x87,
-	0xb0, 0x97, 0x87, 0x49, 0x46, 0x4d, 0x80, 0x81, 0x69, 0x4e, 0xad, 0xf7, 0x68, 0xf8, 0x12, 0x1e,
-	0x1b, 0xbb, 0x2a, 0xa0, 0x37, 0x19, 0x55, 0x1a, 0x3b, 0x60, 0x2f, 0x58, 0xa2, 0xa9, 0x54, 0x0e,
-	0xaa, 0xbc, 0x35, 0xed, 0xf0, 0x0a, 0x9e, 0xdc, 0x73, 0x95, 0xe0, 0xa9, 0xa2, 0xf8, 0x1c, 0x6c,
-	0x61, 0xa0, 0x8a, 0xdc, 0x1f, 0xbf, 0xda, 0x25, 0xa2, 0x3a, 0xf2, 0x66, 0xc4, 0xf8, 0x27, 0x82,
-	0x47, 0x67, 0xeb, 0x54, 0x9c, 0x83, 0x5d, 0xaf, 0xc4, 0x6f, 0x77, 0x99, 0xdc, 0x5c, 0xe3, 0xbe,
-	0xdb, 0x51, 0x65, 0xee, 0x9a, 0x2c, 0x56, 0x77, 0x5e, 0xeb, 0xf7, 0x9d, 0xd7, 0xfa, 0x51, 0x78,
-	0x68, 0x55, 0x78, 0xe8, 0x57, 0xe1, 0xa1, 0x3f, 0x85, 0x87, 0xbe, 0x9c, 0xff, 0xdf, 0x5b, 0xfc,
-	0xb0, 0x01, 0x7c, 0xb6, 0x66, 0xdd, 0xea, 0xf7, 0x7f, 0xf3, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xe6,
-	0x72, 0xde, 0x35, 0xe4, 0x03, 0x00, 0x00,
+	// 549 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
+	0x10, 0xad, 0x9d, 0x34, 0x6e, 0x37, 0xa5, 0xa0, 0x55, 0x55, 0x2c, 0x83, 0x9c, 0x28, 0xe2, 0x10,
+	0x21, 0x58, 0xab, 0x01, 0x24, 0x5a, 0x24, 0x0e, 0x51, 0x73, 0x88, 0xd4, 0x43, 0xe5, 0xa8, 0x08,
+	0x71, 0xa9, 0x1c, 0x67, 0x63, 0x56, 0x38, 0xde, 0xed, 0xee, 0xda, 0x22, 0x37, 0x3e, 0x2f, 0x47,
+	0x8e, 0x9c, 0x02, 0xf5, 0x37, 0xf0, 0x01, 0xc8, 0xbb, 0x76, 0x9a, 0xdc, 0x12, 0x71, 0x9b, 0x79,
+	0x33, 0x6f, 0xe6, 0xcd, 0xf3, 0xca, 0xc0, 0x8f, 0x88, 0xfc, 0x9a, 0x8e, 0x51, 0x48, 0x67, 0x5e,
+	0x48, 0x13, 0x19, 0x90, 0x04, 0xf3, 0xc9, 0x7a, 0x18, 0x30, 0xe2, 0x09, 0xcc, 0x33, 0x12, 0x62,
+	0xe1, 0x91, 0x44, 0x72, 0x2a, 0x18, 0x0e, 0x25, 0xa1, 0x89, 0x97, 0x9d, 0x6d, 0x02, 0x88, 0x71,
+	0x2a, 0x29, 0x7c, 0xf1, 0xc0, 0x46, 0x15, 0x13, 0x6d, 0x36, 0x66, 0x67, 0xce, 0xf9, 0x56, 0x9b,
+	0xe5, 0x9c, 0x61, 0xe1, 0xb1, 0x38, 0x90, 0x53, 0xca, 0x67, 0x7a, 0x81, 0xf3, 0x34, 0xa2, 0x34,
+	0x8a, 0xb1, 0xc7, 0x59, 0xe8, 0x09, 0x19, 0xc8, 0x54, 0x94, 0x85, 0x67, 0x65, 0x41, 0x65, 0xe3,
+	0x74, 0xea, 0xe1, 0x19, 0x93, 0xf3, 0xb2, 0x78, 0x12, 0xd1, 0x88, 0xaa, 0xd0, 0x2b, 0x22, 0x8d,
+	0x76, 0xfe, 0x9a, 0xa0, 0x71, 0x1d, 0xa7, 0x11, 0x49, 0x20, 0x04, 0xf5, 0x62, 0x9d, 0x6d, 0xb4,
+	0x8d, 0xee, 0xa1, 0xaf, 0x62, 0x78, 0x0a, 0x4c, 0x32, 0xb1, 0xcd, 0x02, 0xe9, 0x37, 0xf2, 0x65,
+	0xcb, 0x1c, 0x5e, 0xfa, 0x26, 0x99, 0x40, 0x07, 0x1c, 0x70, 0x7c, 0x97, 0x12, 0x8e, 0x85, 0x5d,
+	0x6b, 0xd7, 0xba, 0x87, 0xfe, 0x2a, 0x87, 0x1f, 0xc1, 0x61, 0x25, 0x58, 0xd8, 0xf5, 0x76, 0xad,
+	0xdb, 0xec, 0x39, 0x68, 0xcd, 0x13, 0x75, 0x13, 0xba, 0x2e, 0x5b, 0xfa, 0xf5, 0xc5, 0xb2, 0xb5,
+	0xe7, 0x3f, 0x50, 0xe0, 0x08, 0x58, 0xf8, 0x3b, 0xa3, 0x5c, 0x0a, 0x7b, 0x5f, 0xb1, 0xcf, 0xd1,
+	0x36, 0x8e, 0x22, 0x7d, 0x06, 0x1a, 0x68, 0xee, 0x20, 0x91, 0x7c, 0xee, 0x57, 0x93, 0x60, 0x07,
+	0x1c, 0x85, 0x01, 0x0b, 0xc6, 0x24, 0x26, 0x92, 0x60, 0x61, 0x37, 0x94, 0xe8, 0x0d, 0x0c, 0xbe,
+	0x06, 0x07, 0x24, 0x21, 0xf2, 0x16, 0x73, 0x6e, 0x5b, 0x6d, 0xa3, 0xdb, 0xec, 0x41, 0xa4, 0x1d,
+	0x45, 0x9c, 0x85, 0x68, 0xa4, 0xac, 0xf6, 0xad, 0xa2, 0x67, 0xc0, 0xb9, 0x73, 0x01, 0x8e, 0xd6,
+	0x77, 0xc1, 0x27, 0xa0, 0xf6, 0x0d, 0xcf, 0x4b, 0xfb, 0x8a, 0x10, 0x9e, 0x80, 0xfd, 0x2c, 0x88,
+	0x53, 0xac, 0x0d, 0xf4, 0x75, 0x72, 0x61, 0xbe, 0x37, 0x3a, 0x2f, 0xc1, 0xb1, 0x96, 0x2b, 0x7c,
+	0x7c, 0x97, 0x62, 0x21, 0xa1, 0x0d, 0xac, 0x29, 0x89, 0x25, 0xe6, 0xc2, 0x36, 0x94, 0xb6, 0x2a,
+	0xed, 0xdc, 0x82, 0xc7, 0xab, 0x5e, 0xc1, 0x68, 0x22, 0x30, 0xbc, 0x02, 0x16, 0xd3, 0x90, 0x6a,
+	0x6e, 0xf6, 0x5e, 0xed, 0x62, 0x51, 0x69, 0x79, 0x35, 0xa2, 0x83, 0xc0, 0xf1, 0x08, 0xf3, 0x0c,
+	0xf3, 0xd5, 0xfc, 0xe7, 0xa0, 0x9e, 0xa6, 0x64, 0xa2, 0x6f, 0xe9, 0x1f, 0xe4, 0xcb, 0x56, 0xfd,
+	0xe6, 0x66, 0x78, 0xe9, 0x2b, 0xb4, 0xf7, 0xdb, 0x00, 0x8f, 0x86, 0xeb, 0xa3, 0x61, 0x06, 0xac,
+	0x52, 0x22, 0x7c, 0xbb, 0x8b, 0x92, 0xea, 0x7a, 0xe7, 0xdd, 0x8e, 0xac, 0x52, 0xe7, 0x27, 0xd0,
+	0xd0, 0xca, 0xe1, 0x69, 0xf5, 0xa5, 0xaa, 0xb7, 0x8f, 0x06, 0xc5, 0xdb, 0x77, 0xb6, 0x94, 0xb3,
+	0x79, 0x7f, 0x7f, 0xba, 0xb8, 0x77, 0xf7, 0x7e, 0xdd, 0xbb, 0x7b, 0x3f, 0x72, 0xd7, 0x58, 0xe4,
+	0xae, 0xf1, 0x33, 0x77, 0x8d, 0x3f, 0xb9, 0x6b, 0x7c, 0xb9, 0xfa, 0xbf, 0x1f, 0xc6, 0x87, 0x0d,
+	0xe0, 0x73, 0x6d, 0xdc, 0x50, 0x7a, 0xdf, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x0c, 0xb3, 0x50,
+	0xdc, 0x89, 0x04, 0x00, 0x00,
 }
 }
 
 
 // Reference imports to suppress errors if they are not otherwise used.
 // Reference imports to suppress errors if they are not otherwise used.
@@ -254,6 +299,8 @@ type IntrospectionClient interface {
 	// Clients can use this to detect features and capabilities when using
 	// Clients can use this to detect features and capabilities when using
 	// containerd.
 	// containerd.
 	Plugins(ctx context.Context, in *PluginsRequest, opts ...grpc.CallOption) (*PluginsResponse, error)
 	Plugins(ctx context.Context, in *PluginsRequest, opts ...grpc.CallOption) (*PluginsResponse, error)
+	// Server returns information about the containerd server
+	Server(ctx context.Context, in *types1.Empty, opts ...grpc.CallOption) (*ServerResponse, error)
 }
 }
 
 
 type introspectionClient struct {
 type introspectionClient struct {
@@ -273,6 +320,15 @@ func (c *introspectionClient) Plugins(ctx context.Context, in *PluginsRequest, o
 	return out, nil
 	return out, nil
 }
 }
 
 
+func (c *introspectionClient) Server(ctx context.Context, in *types1.Empty, opts ...grpc.CallOption) (*ServerResponse, error) {
+	out := new(ServerResponse)
+	err := c.cc.Invoke(ctx, "/containerd.services.introspection.v1.Introspection/Server", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 // IntrospectionServer is the server API for Introspection service.
 // IntrospectionServer is the server API for Introspection service.
 type IntrospectionServer interface {
 type IntrospectionServer interface {
 	// Plugins returns a list of plugins in containerd.
 	// Plugins returns a list of plugins in containerd.
@@ -280,6 +336,8 @@ type IntrospectionServer interface {
 	// Clients can use this to detect features and capabilities when using
 	// Clients can use this to detect features and capabilities when using
 	// containerd.
 	// containerd.
 	Plugins(context.Context, *PluginsRequest) (*PluginsResponse, error)
 	Plugins(context.Context, *PluginsRequest) (*PluginsResponse, error)
+	// Server returns information about the containerd server
+	Server(context.Context, *types1.Empty) (*ServerResponse, error)
 }
 }
 
 
 func RegisterIntrospectionServer(s *grpc.Server, srv IntrospectionServer) {
 func RegisterIntrospectionServer(s *grpc.Server, srv IntrospectionServer) {
@@ -304,6 +362,24 @@ func _Introspection_Plugins_Handler(srv interface{}, ctx context.Context, dec fu
 	return interceptor(ctx, in, info, handler)
 	return interceptor(ctx, in, info, handler)
 }
 }
 
 
+func _Introspection_Server_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(types1.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(IntrospectionServer).Server(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/containerd.services.introspection.v1.Introspection/Server",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(IntrospectionServer).Server(ctx, req.(*types1.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 var _Introspection_serviceDesc = grpc.ServiceDesc{
 var _Introspection_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "containerd.services.introspection.v1.Introspection",
 	ServiceName: "containerd.services.introspection.v1.Introspection",
 	HandlerType: (*IntrospectionServer)(nil),
 	HandlerType: (*IntrospectionServer)(nil),
@@ -312,6 +388,10 @@ var _Introspection_serviceDesc = grpc.ServiceDesc{
 			MethodName: "Plugins",
 			MethodName: "Plugins",
 			Handler:    _Introspection_Plugins_Handler,
 			Handler:    _Introspection_Plugins_Handler,
 		},
 		},
+		{
+			MethodName: "Server",
+			Handler:    _Introspection_Server_Handler,
+		},
 	},
 	},
 	Streams:  []grpc.StreamDesc{},
 	Streams:  []grpc.StreamDesc{},
 	Metadata: "github.com/containerd/containerd/api/services/introspection/v1/introspection.proto",
 	Metadata: "github.com/containerd/containerd/api/services/introspection/v1/introspection.proto",
@@ -488,6 +568,33 @@ func (m *PluginsResponse) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 	return i, nil
 }
 }
 
 
+func (m *ServerResponse) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *ServerResponse) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.UUID) > 0 {
+		dAtA[i] = 0xa
+		i++
+		i = encodeVarintIntrospection(dAtA, i, uint64(len(m.UUID)))
+		i += copy(dAtA[i:], m.UUID)
+	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
+	return i, nil
+}
+
 func encodeVarintIntrospection(dAtA []byte, offset int, v uint64) int {
 func encodeVarintIntrospection(dAtA []byte, offset int, v uint64) int {
 	for v >= 1<<7 {
 	for v >= 1<<7 {
 		dAtA[offset] = uint8(v&0x7f | 0x80)
 		dAtA[offset] = uint8(v&0x7f | 0x80)
@@ -583,6 +690,22 @@ func (m *PluginsResponse) Size() (n int) {
 	return n
 	return n
 }
 }
 
 
+func (m *ServerResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.UUID)
+	if l > 0 {
+		n += 1 + l + sovIntrospection(uint64(l))
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
 func sovIntrospection(x uint64) (n int) {
 func sovIntrospection(x uint64) (n int) {
 	for {
 	for {
 		n++
 		n++
@@ -645,6 +768,17 @@ func (this *PluginsResponse) String() string {
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
+func (this *ServerResponse) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&ServerResponse{`,
+		`UUID:` + fmt.Sprintf("%v", this.UUID) + `,`,
+		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func valueToStringIntrospection(v interface{}) string {
 func valueToStringIntrospection(v interface{}) string {
 	rv := reflect.ValueOf(v)
 	rv := reflect.ValueOf(v)
 	if rv.IsNil() {
 	if rv.IsNil() {
@@ -1206,6 +1340,92 @@ func (m *PluginsResponse) Unmarshal(dAtA []byte) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+func (m *ServerResponse) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowIntrospection
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: ServerResponse: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: ServerResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowIntrospection
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthIntrospection
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthIntrospection
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.UUID = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipIntrospection(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthIntrospection
+			}
+			if (iNdEx + skippy) < 0 {
+				return ErrInvalidLengthIntrospection
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func skipIntrospection(dAtA []byte) (n int, err error) {
 func skipIntrospection(dAtA []byte) (n int, err error) {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0

+ 7 - 0
vendor/github.com/containerd/containerd/api/services/introspection/v1/introspection.proto

@@ -4,6 +4,7 @@ package containerd.services.introspection.v1;
 
 
 import "github.com/containerd/containerd/api/types/platform.proto";
 import "github.com/containerd/containerd/api/types/platform.proto";
 import "google/rpc/status.proto";
 import "google/rpc/status.proto";
+import "google/protobuf/empty.proto";
 import weak "gogoproto/gogo.proto";
 import weak "gogoproto/gogo.proto";
 
 
 option go_package = "github.com/containerd/containerd/api/services/introspection/v1;introspection";
 option go_package = "github.com/containerd/containerd/api/services/introspection/v1;introspection";
@@ -14,6 +15,8 @@ service Introspection {
 	// Clients can use this to detect features and capabilities when using
 	// Clients can use this to detect features and capabilities when using
 	// containerd.
 	// containerd.
 	rpc Plugins(PluginsRequest) returns (PluginsResponse);
 	rpc Plugins(PluginsRequest) returns (PluginsResponse);
+	// Server returns information about the containerd server
+	rpc Server(google.protobuf.Empty) returns (ServerResponse);
 }
 }
 
 
 message Plugin {
 message Plugin {
@@ -79,3 +82,7 @@ message PluginsRequest {
 message PluginsResponse {
 message PluginsResponse {
 	repeated Plugin plugins = 1 [(gogoproto.nullable) = false];
 	repeated Plugin plugins = 1 [(gogoproto.nullable) = false];
 }
 }
+
+message ServerResponse {
+	string uuid = 1 [(gogoproto.customname) = "UUID"];
+}

File diff suppressed because it is too large
+ 1309 - 96
vendor/github.com/containerd/containerd/api/services/leases/v1/leases.pb.go


+ 38 - 0
vendor/github.com/containerd/containerd/api/services/leases/v1/leases.proto

@@ -22,6 +22,15 @@ service Leases {
 	// List lists all active leases, returning the full list of
 	// List lists all active leases, returning the full list of
 	// leases and optionally including the referenced resources.
 	// leases and optionally including the referenced resources.
 	rpc List(ListRequest) returns (ListResponse);
 	rpc List(ListRequest) returns (ListResponse);
+
+	// AddResource references the resource by the provided lease.
+	rpc AddResource(AddResourceRequest) returns (google.protobuf.Empty);
+
+	// DeleteResource dereferences the resource by the provided lease.
+	rpc DeleteResource(DeleteResourceRequest) returns (google.protobuf.Empty);
+
+	// ListResources lists all the resources referenced by the lease.
+	rpc ListResources(ListResourcesRequest) returns (ListResourcesResponse);
 }
 }
 
 
 // Lease is an object which retains resources while it exists.
 // Lease is an object which retains resources while it exists.
@@ -62,3 +71,32 @@ message ListRequest {
 message ListResponse {
 message ListResponse {
 	repeated Lease leases = 1;
 	repeated Lease leases = 1;
 }
 }
+
+message Resource {
+	string id = 1;
+
+	// For snapshotter resource, there are many snapshotter types here, like
+	// overlayfs, devmapper etc. The type will be formatted with type,
+	// like "snapshotter/overlayfs".
+	string type = 2;
+}
+
+message AddResourceRequest {
+	string id = 1;
+
+	Resource resource = 2 [(gogoproto.nullable) = false];
+}
+
+message DeleteResourceRequest {
+	string id = 1;
+
+	Resource resource = 2 [(gogoproto.nullable) = false];
+}
+
+message ListResourcesRequest {
+	string id = 1;
+}
+
+message ListResourcesResponse {
+	repeated Resource resources = 1	[(gogoproto.nullable) = false];
+}

+ 1 - 1
vendor/github.com/containerd/containerd/archive/compression/compression.go

@@ -180,7 +180,7 @@ func DecompressStream(archive io.Reader) (DecompressReadCloser, error) {
 	}
 	}
 }
 }
 
 
-// CompressStream compresseses the dest with specified compression algorithm.
+// CompressStream compresses the dest with specified compression algorithm.
 func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
 func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
 	switch compression {
 	switch compression {
 	case Uncompressed:
 	case Uncompressed:

+ 150 - 107
vendor/github.com/containerd/containerd/archive/tar.go

@@ -19,9 +19,7 @@ package archive
 import (
 import (
 	"archive/tar"
 	"archive/tar"
 	"context"
 	"context"
-	"fmt"
 	"io"
 	"io"
-	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"runtime"
 	"runtime"
@@ -91,11 +89,6 @@ const (
 	// archives.
 	// archives.
 	whiteoutMetaPrefix = whiteoutPrefix + whiteoutPrefix
 	whiteoutMetaPrefix = whiteoutPrefix + whiteoutPrefix
 
 
-	// whiteoutLinkDir is a directory AUFS uses for storing hardlink links to other
-	// layers. Normally these should not go into exported archives and all changed
-	// hardlinks should be copied to the top layer.
-	whiteoutLinkDir = whiteoutMetaPrefix + "plnk"
-
 	// whiteoutOpaqueDir file means directory has been made opaque - meaning
 	// whiteoutOpaqueDir file means directory has been made opaque - meaning
 	// readdir calls to this directory do not follow to lower layers.
 	// readdir calls to this directory do not follow to lower layers.
 	whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
 	whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
@@ -117,11 +110,15 @@ func Apply(ctx context.Context, root string, r io.Reader, opts ...ApplyOpt) (int
 	if options.Filter == nil {
 	if options.Filter == nil {
 		options.Filter = all
 		options.Filter = all
 	}
 	}
+	if options.applyFunc == nil {
+		options.applyFunc = applyNaive
+	}
 
 
-	return apply(ctx, root, tar.NewReader(r), options)
+	return options.applyFunc(ctx, root, tar.NewReader(r), options)
 }
 }
 
 
-// applyNaive applies a tar stream of an OCI style diff tar.
+// applyNaive applies a tar stream of an OCI style diff tar to a directory
+// applying each file as either a whole file or whiteout.
 // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
 // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
 func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
 func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
 	var (
 	var (
@@ -131,11 +128,49 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
 		// may occur out of order
 		// may occur out of order
 		unpackedPaths = make(map[string]struct{})
 		unpackedPaths = make(map[string]struct{})
 
 
-		// Used for aufs plink directory
-		aufsTempdir   = ""
-		aufsHardlinks = make(map[string]*tar.Header)
+		convertWhiteout = options.ConvertWhiteout
 	)
 	)
 
 
+	if convertWhiteout == nil {
+		// handle whiteouts by removing the target files
+		convertWhiteout = func(hdr *tar.Header, path string) (bool, error) {
+			base := filepath.Base(path)
+			dir := filepath.Dir(path)
+			if base == whiteoutOpaqueDir {
+				_, err := os.Lstat(dir)
+				if err != nil {
+					return false, err
+				}
+				err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+					if err != nil {
+						if os.IsNotExist(err) {
+							err = nil // parent was deleted
+						}
+						return err
+					}
+					if path == dir {
+						return nil
+					}
+					if _, exists := unpackedPaths[path]; !exists {
+						err := os.RemoveAll(path)
+						return err
+					}
+					return nil
+				})
+				return false, err
+			}
+
+			if strings.HasPrefix(base, whiteoutPrefix) {
+				originalBase := base[len(whiteoutPrefix):]
+				originalPath := filepath.Join(dir, originalBase)
+
+				return false, os.RemoveAll(originalPath)
+			}
+
+			return true, nil
+		}
+	}
+
 	// Iterate through the files in the archive.
 	// Iterate through the files in the archive.
 	for {
 	for {
 		select {
 		select {
@@ -193,85 +228,21 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
 			if base == "" {
 			if base == "" {
 				parentPath = filepath.Dir(path)
 				parentPath = filepath.Dir(path)
 			}
 			}
-			if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
-				err = mkdirAll(parentPath, 0755)
-				if err != nil {
-					return 0, err
-				}
+			if err := mkparent(ctx, parentPath, root, options.Parents); err != nil {
+				return 0, err
 			}
 			}
 		}
 		}
 
 
-		// Skip AUFS metadata dirs
-		if strings.HasPrefix(hdr.Name, whiteoutMetaPrefix) {
-			// Regular files inside /.wh..wh.plnk can be used as hardlink targets
-			// We don't want this directory, but we need the files in them so that
-			// such hardlinks can be resolved.
-			if strings.HasPrefix(hdr.Name, whiteoutLinkDir) && hdr.Typeflag == tar.TypeReg {
-				basename := filepath.Base(hdr.Name)
-				aufsHardlinks[basename] = hdr
-				if aufsTempdir == "" {
-					if aufsTempdir, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "dockerplnk"); err != nil {
-						return 0, err
-					}
-					defer os.RemoveAll(aufsTempdir)
-				}
-				p, err := fs.RootPath(aufsTempdir, basename)
-				if err != nil {
-					return 0, err
-				}
-				if err := createTarFile(ctx, p, root, hdr, tr); err != nil {
-					return 0, err
-				}
-			}
-
-			if hdr.Name != whiteoutOpaqueDir {
-				continue
-			}
+		// Naive whiteout convert function which handles whiteout files by
+		// removing the target files.
+		if err := validateWhiteout(path); err != nil {
+			return 0, err
 		}
 		}
-
-		if strings.HasPrefix(base, whiteoutPrefix) {
-			dir := filepath.Dir(path)
-			if base == whiteoutOpaqueDir {
-				_, err := os.Lstat(dir)
-				if err != nil {
-					return 0, err
-				}
-				err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
-					if err != nil {
-						if os.IsNotExist(err) {
-							err = nil // parent was deleted
-						}
-						return err
-					}
-					if path == dir {
-						return nil
-					}
-					if _, exists := unpackedPaths[path]; !exists {
-						err := os.RemoveAll(path)
-						return err
-					}
-					return nil
-				})
-				if err != nil {
-					return 0, err
-				}
-				continue
-			}
-
-			originalBase := base[len(whiteoutPrefix):]
-			originalPath := filepath.Join(dir, originalBase)
-
-			// Ensure originalPath is under dir
-			if dir[len(dir)-1] != filepath.Separator {
-				dir += string(filepath.Separator)
-			}
-			if !strings.HasPrefix(originalPath, dir) {
-				return 0, errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base)
-			}
-
-			if err := os.RemoveAll(originalPath); err != nil {
-				return 0, err
-			}
+		writeFile, err := convertWhiteout(hdr, path)
+		if err != nil {
+			return 0, errors.Wrapf(err, "failed to convert whiteout file %q", hdr.Name)
+		}
+		if !writeFile {
 			continue
 			continue
 		}
 		}
 		// If path exits we almost always just want to remove and replace it.
 		// If path exits we almost always just want to remove and replace it.
@@ -289,26 +260,6 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
 		srcData := io.Reader(tr)
 		srcData := io.Reader(tr)
 		srcHdr := hdr
 		srcHdr := hdr
 
 
-		// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
-		// we manually retarget these into the temporary files we extracted them into
-		if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), whiteoutLinkDir) {
-			linkBasename := filepath.Base(hdr.Linkname)
-			srcHdr = aufsHardlinks[linkBasename]
-			if srcHdr == nil {
-				return 0, fmt.Errorf("invalid aufs hardlink")
-			}
-			p, err := fs.RootPath(aufsTempdir, linkBasename)
-			if err != nil {
-				return 0, err
-			}
-			tmpFile, err := os.Open(p)
-			if err != nil {
-				return 0, err
-			}
-			defer tmpFile.Close()
-			srcData = tmpFile
-		}
-
 		if err := createTarFile(ctx, path, root, srcHdr, srcData); err != nil {
 		if err := createTarFile(ctx, path, root, srcHdr, srcData); err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
@@ -428,6 +379,66 @@ func createTarFile(ctx context.Context, path, extractDir string, hdr *tar.Header
 	return chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime))
 	return chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime))
 }
 }
 
 
+func mkparent(ctx context.Context, path, root string, parents []string) error {
+	if dir, err := os.Lstat(path); err == nil {
+		if dir.IsDir() {
+			return nil
+		}
+		return &os.PathError{
+			Op:   "mkparent",
+			Path: path,
+			Err:  syscall.ENOTDIR,
+		}
+	} else if !os.IsNotExist(err) {
+		return err
+	}
+
+	i := len(path)
+	for i > len(root) && !os.IsPathSeparator(path[i-1]) {
+		i--
+	}
+
+	if i > len(root)+1 {
+		if err := mkparent(ctx, path[:i-1], root, parents); err != nil {
+			return err
+		}
+	}
+
+	if err := mkdir(path, 0755); err != nil {
+		// Check that still doesn't exist
+		dir, err1 := os.Lstat(path)
+		if err1 == nil && dir.IsDir() {
+			return nil
+		}
+		return err
+	}
+
+	for _, p := range parents {
+		ppath, err := fs.RootPath(p, path[len(root):])
+		if err != nil {
+			return err
+		}
+
+		dir, err := os.Lstat(ppath)
+		if err == nil {
+			if !dir.IsDir() {
+				// Replaced, do not copy attributes
+				break
+			}
+			if err := copyDirInfo(dir, path); err != nil {
+				return err
+			}
+			return copyUpXAttrs(path, ppath)
+		} else if !os.IsNotExist(err) {
+			return err
+		}
+	}
+
+	log.G(ctx).Debugf("parent directory %q not found: default permissions(0755) used", path)
+
+	return nil
+}
+
 type changeWriter struct {
 type changeWriter struct {
 	tw        *tar.Writer
 	tw        *tar.Writer
 	source    string
 	source    string
@@ -493,6 +504,12 @@ func (cw *changeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 
 
 		hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
 		hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
 
 
+		// truncate timestamp for compatibility. without PAX stdlib rounds timestamps instead
+		hdr.Format = tar.FormatPAX
+		hdr.ModTime = hdr.ModTime.Truncate(time.Second)
+		hdr.AccessTime = time.Time{}
+		hdr.ChangeTime = time.Time{}
+
 		name := p
 		name := p
 		if strings.HasPrefix(name, string(filepath.Separator)) {
 		if strings.HasPrefix(name, string(filepath.Separator)) {
 			name, err = filepath.Rel(string(filepath.Separator), name)
 			name, err = filepath.Rel(string(filepath.Separator), name)
@@ -598,6 +615,9 @@ func (cw *changeWriter) Close() error {
 }
 }
 
 
 func (cw *changeWriter) includeParents(hdr *tar.Header) error {
 func (cw *changeWriter) includeParents(hdr *tar.Header) error {
+	if cw.addedDirs == nil {
+		return nil
+	}
 	name := strings.TrimRight(hdr.Name, "/")
 	name := strings.TrimRight(hdr.Name, "/")
 	fname := filepath.Join(cw.source, name)
 	fname := filepath.Join(cw.source, name)
 	parent := filepath.Dir(name)
 	parent := filepath.Dir(name)
@@ -684,3 +704,26 @@ func hardlinkRootPath(root, linkname string) (string, error) {
 	}
 	}
 	return targetPath, nil
 	return targetPath, nil
 }
 }
+
+func validateWhiteout(path string) error {
+	base := filepath.Base(path)
+	dir := filepath.Dir(path)
+
+	if base == whiteoutOpaqueDir {
+		return nil
+	}
+
+	if strings.HasPrefix(base, whiteoutPrefix) {
+		originalBase := base[len(whiteoutPrefix):]
+		originalPath := filepath.Join(dir, originalBase)
+
+		// Ensure originalPath is under dir
+		if dir[len(dir)-1] != filepath.Separator {
+			dir += string(filepath.Separator)
+		}
+		if !strings.HasPrefix(originalPath, dir) {
+			return errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base)
+		}
+	}
+	return nil
+}

+ 37 - 1
vendor/github.com/containerd/containerd/archive/tar_opts.go

@@ -16,7 +16,19 @@
 
 
 package archive
 package archive
 
 
-import "archive/tar"
+import (
+	"archive/tar"
+	"context"
+)
+
+// ApplyOptions provides additional options for an Apply operation
+type ApplyOptions struct {
+	Filter          Filter          // Filter tar headers
+	ConvertWhiteout ConvertWhiteout // Convert whiteout files
+	Parents         []string        // Parent directories to handle inherited attributes without CoW
+
+	applyFunc func(context.Context, string, *tar.Reader, ApplyOptions) (int64, error)
+}
 
 
 // ApplyOpt allows setting mutable archive apply properties on creation
 // ApplyOpt allows setting mutable archive apply properties on creation
 type ApplyOpt func(options *ApplyOptions) error
 type ApplyOpt func(options *ApplyOptions) error
@@ -24,6 +36,9 @@ type ApplyOpt func(options *ApplyOptions) error
 // Filter specific files from the archive
 // Filter specific files from the archive
 type Filter func(*tar.Header) (bool, error)
 type Filter func(*tar.Header) (bool, error)
 
 
+// ConvertWhiteout converts whiteout files from the archive
+type ConvertWhiteout func(*tar.Header, string) (bool, error)
+
 // all allows all files
 // all allows all files
 func all(_ *tar.Header) (bool, error) {
 func all(_ *tar.Header) (bool, error) {
 	return true, nil
 	return true, nil
@@ -36,3 +51,24 @@ func WithFilter(f Filter) ApplyOpt {
 		return nil
 		return nil
 	}
 	}
 }
 }
+
+// WithConvertWhiteout uses the convert function to convert the whiteout files.
+func WithConvertWhiteout(c ConvertWhiteout) ApplyOpt {
+	return func(options *ApplyOptions) error {
+		options.ConvertWhiteout = c
+		return nil
+	}
+}
+
+// WithParents provides parent directories for resolving inherited attributes
+// directory from the filesystem.
+// Inherited attributes are searched from first to last, making the first
+// element in the list the most immediate parent directory.
+// NOTE: When applying to a filesystem which supports CoW, file attributes
+// should be inherited by the filesystem.
+func WithParents(p []string) ApplyOpt {
+	return func(options *ApplyOptions) error {
+		options.Parents = p
+		return nil
+	}
+}

+ 59 - 0
vendor/github.com/containerd/containerd/archive/tar_opts_linux.go

@@ -0,0 +1,59 @@
+// +build linux
+
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package archive
+
+import (
+	"archive/tar"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"golang.org/x/sys/unix"
+)
+
+// AufsConvertWhiteout converts whiteout files for aufs.
+func AufsConvertWhiteout(_ *tar.Header, _ string) (bool, error) {
+	return true, nil
+}
+
+// OverlayConvertWhiteout converts whiteout files for overlay.
+func OverlayConvertWhiteout(hdr *tar.Header, path string) (bool, error) {
+	base := filepath.Base(path)
+	dir := filepath.Dir(path)
+
+	// if a directory is marked as opaque, we need to translate that to overlay
+	if base == whiteoutOpaqueDir {
+		// don't write the file itself
+		return false, unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0)
+	}
+
+	// if a file was deleted and we are using overlay, we need to create a character device
+	if strings.HasPrefix(base, whiteoutPrefix) {
+		originalBase := base[len(whiteoutPrefix):]
+		originalPath := filepath.Join(dir, originalBase)
+
+		if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil {
+			return false, err
+		}
+		// don't write the file itself
+		return false, os.Chown(originalPath, hdr.Uid, hdr.Gid)
+	}
+
+	return true, nil
+}

+ 1 - 17
vendor/github.com/containerd/containerd/archive/tar_opts_windows.go

@@ -18,28 +18,12 @@
 
 
 package archive
 package archive
 
 
-// ApplyOptions provides additional options for an Apply operation
-type ApplyOptions struct {
-	ParentLayerPaths        []string // Parent layer paths used for Windows layer apply
-	IsWindowsContainerLayer bool     // True if the tar stream to be applied is a Windows Container Layer
-	Filter                  Filter   // Filter tar headers
-}
-
-// WithParentLayers adds parent layers to the apply process this is required
-// for all Windows layers except the base layer.
-func WithParentLayers(parentPaths []string) ApplyOpt {
-	return func(options *ApplyOptions) error {
-		options.ParentLayerPaths = parentPaths
-		return nil
-	}
-}
-
 // AsWindowsContainerLayer indicates that the tar stream to apply is that of
 // AsWindowsContainerLayer indicates that the tar stream to apply is that of
 // a Windows Container Layer. The caller must be holding SeBackupPrivilege and
 // a Windows Container Layer. The caller must be holding SeBackupPrivilege and
 // SeRestorePrivilege.
 // SeRestorePrivilege.
 func AsWindowsContainerLayer() ApplyOpt {
 func AsWindowsContainerLayer() ApplyOpt {
 	return func(options *ApplyOptions) error {
 	return func(options *ApplyOptions) error {
-		options.IsWindowsContainerLayer = true
+		options.applyFunc = applyWindowsLayer
 		return nil
 		return nil
 	}
 	}
 }
 }

+ 67 - 10
vendor/github.com/containerd/containerd/archive/tar_unix.go

@@ -20,11 +20,12 @@ package archive
 
 
 import (
 import (
 	"archive/tar"
 	"archive/tar"
-	"context"
 	"os"
 	"os"
+	"strings"
 	"sync"
 	"sync"
 	"syscall"
 	"syscall"
 
 
+	"github.com/containerd/continuity/fs"
 	"github.com/containerd/continuity/sysx"
 	"github.com/containerd/continuity/sysx"
 	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -74,10 +75,6 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
 	return f, err
 	return f, err
 }
 }
 
 
-func mkdirAll(path string, perm os.FileMode) error {
-	return os.MkdirAll(path, perm)
-}
-
 func mkdir(path string, perm os.FileMode) error {
 func mkdir(path string, perm os.FileMode) error {
 	if err := os.Mkdir(path, perm); err != nil {
 	if err := os.Mkdir(path, perm); err != nil {
 		return err
 		return err
@@ -149,11 +146,71 @@ func getxattr(path, attr string) ([]byte, error) {
 }
 }
 
 
 func setxattr(path, key, value string) error {
 func setxattr(path, key, value string) error {
-	return sysx.LSetxattr(path, key, []byte(value), 0)
+	// Do not set trusted attributes
+	if strings.HasPrefix(key, "trusted.") {
+		return errors.Wrap(unix.ENOTSUP, "admin attributes from archive not supported")
+	}
+	return unix.Lsetxattr(path, key, []byte(value), 0)
+}
+
+func copyDirInfo(fi os.FileInfo, path string) error {
+	st := fi.Sys().(*syscall.Stat_t)
+	if err := os.Lchown(path, int(st.Uid), int(st.Gid)); err != nil {
+		if os.IsPermission(err) {
+			// Normally if uid/gid are the same this would be a no-op, but some
+			// filesystems may still return EPERM... for instance NFS does this.
+			// In such a case, this is not an error.
+			if dstStat, err2 := os.Lstat(path); err2 == nil {
+				st2 := dstStat.Sys().(*syscall.Stat_t)
+				if st.Uid == st2.Uid && st.Gid == st2.Gid {
+					err = nil
+				}
+			}
+		}
+		if err != nil {
+			return errors.Wrapf(err, "failed to chown %s", path)
+		}
+	}
+
+	if err := os.Chmod(path, fi.Mode()); err != nil {
+		return errors.Wrapf(err, "failed to chmod %s", path)
+	}
+
+	timespec := []unix.Timespec{unix.Timespec(fs.StatAtime(st)), unix.Timespec(fs.StatMtime(st))}
+	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
+		return errors.Wrapf(err, "failed to utime %s", path)
+	}
+
+	return nil
 }
 }
 
 
-// apply applies a tar stream of an OCI style diff tar.
-// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
-func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
-	return applyNaive(ctx, root, tr, options)
+func copyUpXAttrs(dst, src string) error {
+	xattrKeys, err := sysx.LListxattr(src)
+	if err != nil {
+		if err == unix.ENOTSUP || err == sysx.ENODATA {
+			return nil
+		}
+		return errors.Wrapf(err, "failed to list xattrs on %s", src)
+	}
+	for _, xattr := range xattrKeys {
+		// Do not copy up trusted attributes
+		if strings.HasPrefix(xattr, "trusted.") {
+			continue
+		}
+		data, err := sysx.LGetxattr(src, xattr)
+		if err != nil {
+			if err == unix.ENOTSUP || err == sysx.ENODATA {
+				continue
+			}
+			return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
+		}
+		if err := unix.Lsetxattr(dst, xattr, data, unix.XATTR_CREATE); err != nil {
+			if err == unix.ENOTSUP || err == unix.ENODATA || err == unix.EEXIST {
+				continue
+			}
+			return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
+		}
+	}
+
+	return nil
 }
 }

+ 15 - 16
vendor/github.com/containerd/containerd/archive/tar_windows.go

@@ -23,7 +23,6 @@ import (
 	"bufio"
 	"bufio"
 	"context"
 	"context"
 	"encoding/base64"
 	"encoding/base64"
-	"errors"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"os"
 	"os"
@@ -36,6 +35,7 @@ import (
 	"github.com/Microsoft/go-winio"
 	"github.com/Microsoft/go-winio"
 	"github.com/Microsoft/hcsshim"
 	"github.com/Microsoft/hcsshim"
 	"github.com/containerd/containerd/sys"
 	"github.com/containerd/containerd/sys"
+	"github.com/pkg/errors"
 )
 )
 
 
 const (
 const (
@@ -107,10 +107,6 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
 	return sys.OpenFileSequential(name, flag, perm)
 	return sys.OpenFileSequential(name, flag, perm)
 }
 }
 
 
-func mkdirAll(path string, perm os.FileMode) error {
-	return sys.MkdirAll(path, perm)
-}
-
 func mkdir(path string, perm os.FileMode) error {
 func mkdir(path string, perm os.FileMode) error {
 	return os.Mkdir(path, perm)
 	return os.Mkdir(path, perm)
 }
 }
@@ -153,16 +149,8 @@ func setxattr(path, key, value string) error {
 	return errors.New("xattrs not supported on Windows")
 	return errors.New("xattrs not supported on Windows")
 }
 }
 
 
-// apply applies a tar stream of an OCI style diff tar of a Windows layer.
-// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
-func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
-	if options.IsWindowsContainerLayer {
-		return applyWindowsLayer(ctx, root, tr, options)
-	}
-	return applyNaive(ctx, root, tr, options)
-}
-
-// applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows layer.
+// applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows
+// layer using the hcsshim layer writer and backup streams.
 // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
 // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
 func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
 func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
 	home, id := filepath.Split(root)
 	home, id := filepath.Split(root)
@@ -170,7 +158,7 @@ func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options
 		HomeDir: home,
 		HomeDir: home,
 	}
 	}
 
 
-	w, err := hcsshim.NewLayerWriter(info, id, options.ParentLayerPaths)
+	w, err := hcsshim.NewLayerWriter(info, id, options.Parents)
 	if err != nil {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
@@ -443,3 +431,14 @@ func writeBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
 		}
 		}
 	}
 	}
 }
 }
+
+func copyDirInfo(fi os.FileInfo, path string) error {
+	if err := os.Chmod(path, fi.Mode()); err != nil {
+		return errors.Wrapf(err, "failed to chmod %s", path)
+	}
+	return nil
+}
+
+func copyUpXAttrs(dst, src string) error {
+	return nil
+}

+ 1 - 1
vendor/github.com/containerd/containerd/archive/time_unix.go

@@ -32,7 +32,7 @@ func chtimes(path string, atime, mtime time.Time) error {
 	utimes[1] = unix.NsecToTimespec(mtime.UnixNano())
 	utimes[1] = unix.NsecToTimespec(mtime.UnixNano())
 
 
 	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
 	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
-		return errors.Wrap(err, "failed call to UtimesNanoAt")
+		return errors.Wrapf(err, "failed call to UtimesNanoAt for %s", path)
 	}
 	}
 
 
 	return nil
 	return nil

+ 22 - 7
vendor/github.com/containerd/containerd/cio/io.go

@@ -18,10 +18,13 @@ package cio
 
 
 import (
 import (
 	"context"
 	"context"
+	"errors"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"net/url"
 	"net/url"
 	"os"
 	"os"
+	"path/filepath"
+	"strings"
 	"sync"
 	"sync"
 
 
 	"github.com/containerd/containerd/defaults"
 	"github.com/containerd/containerd/defaults"
@@ -242,17 +245,24 @@ func LogURI(uri *url.URL) Creator {
 // BinaryIO forwards container STDOUT|STDERR directly to a logging binary
 // BinaryIO forwards container STDOUT|STDERR directly to a logging binary
 func BinaryIO(binary string, args map[string]string) Creator {
 func BinaryIO(binary string, args map[string]string) Creator {
 	return func(_ string) (IO, error) {
 	return func(_ string) (IO, error) {
+		binary = filepath.Clean(binary)
+		if !strings.HasPrefix(binary, "/") {
+			return nil, errors.New("absolute path needed")
+		}
 		uri := &url.URL{
 		uri := &url.URL{
 			Scheme: "binary",
 			Scheme: "binary",
-			Host:   binary,
+			Path:   binary,
 		}
 		}
+		q := uri.Query()
 		for k, v := range args {
 		for k, v := range args {
-			uri.Query().Set(k, v)
+			q.Set(k, v)
 		}
 		}
+		uri.RawQuery = q.Encode()
+		res := uri.String()
 		return &logURI{
 		return &logURI{
 			config: Config{
 			config: Config{
-				Stdout: uri.String(),
-				Stderr: uri.String(),
+				Stdout: res,
+				Stderr: res,
 			},
 			},
 		}, nil
 		}, nil
 	}
 	}
@@ -262,14 +272,19 @@ func BinaryIO(binary string, args map[string]string) Creator {
 // If the log file already exists, the logs will be appended to the file.
 // If the log file already exists, the logs will be appended to the file.
 func LogFile(path string) Creator {
 func LogFile(path string) Creator {
 	return func(_ string) (IO, error) {
 	return func(_ string) (IO, error) {
+		path = filepath.Clean(path)
+		if !strings.HasPrefix(path, "/") {
+			return nil, errors.New("absolute path needed")
+		}
 		uri := &url.URL{
 		uri := &url.URL{
 			Scheme: "file",
 			Scheme: "file",
-			Host:   path,
+			Path:   path,
 		}
 		}
+		res := uri.String()
 		return &logURI{
 		return &logURI{
 			config: Config{
 			config: Config{
-				Stdout: uri.String(),
-				Stderr: uri.String(),
+				Stdout: res,
+				Stderr: res,
 			},
 			},
 		}, nil
 		}, nil
 	}
 	}

+ 12 - 10
vendor/github.com/containerd/containerd/cio/io_unix.go

@@ -72,17 +72,19 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) {
 	}
 	}
 
 
 	var wg = &sync.WaitGroup{}
 	var wg = &sync.WaitGroup{}
-	wg.Add(1)
-	go func() {
-		p := bufPool.Get().(*[]byte)
-		defer bufPool.Put(p)
-
-		io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p)
-		pipes.Stdout.Close()
-		wg.Done()
-	}()
+	if fifos.Stdout != "" {
+		wg.Add(1)
+		go func() {
+			p := bufPool.Get().(*[]byte)
+			defer bufPool.Put(p)
+
+			io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p)
+			pipes.Stdout.Close()
+			wg.Done()
+		}()
+	}
 
 
-	if !fifos.Terminal {
+	if !fifos.Terminal && fifos.Stderr != "" {
 		wg.Add(1)
 		wg.Add(1)
 		go func() {
 		go func() {
 			p := bufPool.Get().(*[]byte)
 			p := bufPool.Get().(*[]byte)

+ 124 - 33
vendor/github.com/containerd/containerd/client.go

@@ -43,6 +43,7 @@ import (
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
 	contentproxy "github.com/containerd/containerd/content/proxy"
 	contentproxy "github.com/containerd/containerd/content/proxy"
 	"github.com/containerd/containerd/defaults"
 	"github.com/containerd/containerd/defaults"
+	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/events"
 	"github.com/containerd/containerd/events"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/leases"
 	"github.com/containerd/containerd/leases"
@@ -56,6 +57,7 @@ import (
 	"github.com/containerd/containerd/snapshots"
 	"github.com/containerd/containerd/snapshots"
 	snproxy "github.com/containerd/containerd/snapshots/proxy"
 	snproxy "github.com/containerd/containerd/snapshots/proxy"
 	"github.com/containerd/typeurl"
 	"github.com/containerd/typeurl"
+	"github.com/gogo/protobuf/types"
 	ptypes "github.com/gogo/protobuf/types"
 	ptypes "github.com/gogo/protobuf/types"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
@@ -86,13 +88,23 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
 	if copts.timeout == 0 {
 	if copts.timeout == 0 {
 		copts.timeout = 10 * time.Second
 		copts.timeout = 10 * time.Second
 	}
 	}
-	rt := fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS)
+
+	c := &Client{
+		defaultns: copts.defaultns,
+	}
+
 	if copts.defaultRuntime != "" {
 	if copts.defaultRuntime != "" {
-		rt = copts.defaultRuntime
+		c.runtime = copts.defaultRuntime
+	} else {
+		c.runtime = defaults.DefaultRuntime
 	}
 	}
-	c := &Client{
-		runtime: rt,
+
+	if copts.defaultPlatform != nil {
+		c.platform = copts.defaultPlatform
+	} else {
+		c.platform = platforms.Default()
 	}
 	}
+
 	if copts.services != nil {
 	if copts.services != nil {
 		c.services = *copts.services
 		c.services = *copts.services
 	}
 	}
@@ -102,7 +114,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
 			grpc.WithInsecure(),
 			grpc.WithInsecure(),
 			grpc.FailOnNonTempDialError(true),
 			grpc.FailOnNonTempDialError(true),
 			grpc.WithBackoffMaxDelay(3 * time.Second),
 			grpc.WithBackoffMaxDelay(3 * time.Second),
-			grpc.WithDialer(dialer.Dialer),
+			grpc.WithContextDialer(dialer.ContextDialer),
 
 
 			// TODO(stevvooe): We may need to allow configuration of this on the client.
 			// TODO(stevvooe): We may need to allow configuration of this on the client.
 			grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
 			grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
@@ -134,19 +146,15 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
 		c.conn, c.connector = conn, connector
 		c.conn, c.connector = conn, connector
 	}
 	}
 	if copts.services == nil && c.conn == nil {
 	if copts.services == nil && c.conn == nil {
-		return nil, errors.New("no grpc connection or services is available")
+		return nil, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection or services is available")
 	}
 	}
 
 
 	// check namespace labels for default runtime
 	// check namespace labels for default runtime
-	if copts.defaultRuntime == "" && copts.defaultns != "" {
-		namespaces := c.NamespaceService()
-		ctx := context.Background()
-		if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil {
-			if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok {
-				c.runtime = defaultRuntime
-			}
-		} else {
+	if copts.defaultRuntime == "" && c.defaultns != "" {
+		if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil {
 			return nil, err
 			return nil, err
+		} else if label != "" {
+			c.runtime = label
 		}
 		}
 	}
 	}
 
 
@@ -163,20 +171,17 @@ func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) {
 		}
 		}
 	}
 	}
 	c := &Client{
 	c := &Client{
-		conn:    conn,
-		runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS),
+		defaultns: copts.defaultns,
+		conn:      conn,
+		runtime:   fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS),
 	}
 	}
 
 
 	// check namespace labels for default runtime
 	// check namespace labels for default runtime
-	if copts.defaultRuntime == "" && copts.defaultns != "" {
-		namespaces := c.NamespaceService()
-		ctx := context.Background()
-		if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil {
-			if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok {
-				c.runtime = defaultRuntime
-			}
-		} else {
+	if copts.defaultRuntime == "" && c.defaultns != "" {
+		if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil {
 			return nil, err
 			return nil, err
+		} else if label != "" {
+			c.runtime = label
 		}
 		}
 	}
 	}
 
 
@@ -193,13 +198,15 @@ type Client struct {
 	connMu    sync.Mutex
 	connMu    sync.Mutex
 	conn      *grpc.ClientConn
 	conn      *grpc.ClientConn
 	runtime   string
 	runtime   string
+	defaultns string
+	platform  platforms.MatchComparer
 	connector func() (*grpc.ClientConn, error)
 	connector func() (*grpc.ClientConn, error)
 }
 }
 
 
 // Reconnect re-establishes the GRPC connection to the containerd daemon
 // Reconnect re-establishes the GRPC connection to the containerd daemon
 func (c *Client) Reconnect() error {
 func (c *Client) Reconnect() error {
 	if c.connector == nil {
 	if c.connector == nil {
-		return errors.New("unable to reconnect to containerd, no connector available")
+		return errors.Wrap(errdefs.ErrUnavailable, "unable to reconnect to containerd, no connector available")
 	}
 	}
 	c.connMu.Lock()
 	c.connMu.Lock()
 	defer c.connMu.Unlock()
 	defer c.connMu.Unlock()
@@ -222,10 +229,10 @@ func (c *Client) IsServing(ctx context.Context) (bool, error) {
 	c.connMu.Lock()
 	c.connMu.Lock()
 	if c.conn == nil {
 	if c.conn == nil {
 		c.connMu.Unlock()
 		c.connMu.Unlock()
-		return false, errors.New("no grpc connection available")
+		return false, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available")
 	}
 	}
 	c.connMu.Unlock()
 	c.connMu.Unlock()
-	r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.FailFast(false))
+	r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true))
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -294,10 +301,14 @@ type RemoteContext struct {
 	PlatformMatcher platforms.MatchComparer
 	PlatformMatcher platforms.MatchComparer
 
 
 	// Unpack is done after an image is pulled to extract into a snapshotter.
 	// Unpack is done after an image is pulled to extract into a snapshotter.
+	// It is done simultaneously for schema 2 images when they are pulled.
 	// If an image is not unpacked on pull, it can be unpacked any time
 	// If an image is not unpacked on pull, it can be unpacked any time
 	// afterwards. Unpacking is required to run an image.
 	// afterwards. Unpacking is required to run an image.
 	Unpack bool
 	Unpack bool
 
 
+	// UnpackOpts handles options to the unpack call.
+	UnpackOpts []UnpackOpt
+
 	// Snapshotter used for unpacking
 	// Snapshotter used for unpacking
 	Snapshotter string
 	Snapshotter string
 
 
@@ -329,9 +340,8 @@ type RemoteContext struct {
 	// MaxConcurrentDownloads is the max concurrent content downloads for each pull.
 	// MaxConcurrentDownloads is the max concurrent content downloads for each pull.
 	MaxConcurrentDownloads int
 	MaxConcurrentDownloads int
 
 
-	// AppendDistributionSourceLabel allows fetcher to add distribute source
-	// label for each blob content, which doesn't work for legacy schema1.
-	AppendDistributionSourceLabel bool
+	// AllMetadata downloads all manifests and known-configuration files
+	AllMetadata bool
 }
 }
 
 
 func defaultRemoteContext() *RemoteContext {
 func defaultRemoteContext() *RemoteContext {
@@ -339,7 +349,6 @@ func defaultRemoteContext() *RemoteContext {
 		Resolver: docker.NewResolver(docker.ResolverOptions{
 		Resolver: docker.NewResolver(docker.ResolverOptions{
 			Client: http.DefaultClient,
 			Client: http.DefaultClient,
 		}),
 		}),
-		Snapshotter: DefaultSnapshotter,
 	}
 	}
 }
 }
 
 
@@ -354,7 +363,7 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
 	}
 	}
 
 
 	if fetchCtx.Unpack {
 	if fetchCtx.Unpack {
-		return images.Image{}, errors.New("unpack on fetch not supported, try pull")
+		return images.Image{}, errors.Wrap(errdefs.ErrNotImplemented, "unpack on fetch not supported, try pull")
 	}
 	}
 
 
 	if fetchCtx.PlatformMatcher == nil {
 	if fetchCtx.PlatformMatcher == nil {
@@ -407,6 +416,11 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor,
 		}
 		}
 	}
 	}
 
 
+	// Annotate ref with digest to push only push tag for single digest
+	if !strings.Contains(ref, "@") {
+		ref = ref + "@" + desc.Digest.String()
+	}
+
 	pusher, err := pushCtx.Resolver.Pusher(ctx, ref)
 	pusher, err := pushCtx.Resolver.Pusher(ctx, ref)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -490,6 +504,27 @@ func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref s
 	return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels))
 	return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels))
 }
 }
 
 
+// GetLabel gets a label value from namespace store
+// If there is no default label, an empty string returned with nil error
+func (c *Client) GetLabel(ctx context.Context, label string) (string, error) {
+	ns, err := namespaces.NamespaceRequired(ctx)
+	if err != nil {
+		if c.defaultns == "" {
+			return "", err
+		}
+		ns = c.defaultns
+	}
+
+	srv := c.NamespaceService()
+	labels, err := srv.Labels(ctx, ns)
+	if err != nil {
+		return "", err
+	}
+
+	value := labels[label]
+	return value, nil
+}
+
 // Subscribe to events that match one or more of the provided filters.
 // Subscribe to events that match one or more of the provided filters.
 //
 //
 // Callers should listen on both the envelope and errs channels. If the errs
 // Callers should listen on both the envelope and errs channels. If the errs
@@ -543,6 +578,10 @@ func (c *Client) ContentStore() content.Store {
 
 
 // SnapshotService returns the underlying snapshotter for the provided snapshotter name
 // SnapshotService returns the underlying snapshotter for the provided snapshotter name
 func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter {
 func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter {
+	snapshotterName, err := c.resolveSnapshotterName(context.Background(), snapshotterName)
+	if err != nil {
+		snapshotterName = DefaultSnapshotter
+	}
 	if c.snapshotters != nil {
 	if c.snapshotters != nil {
 		return c.snapshotters[snapshotterName]
 		return c.snapshotters[snapshotterName]
 	}
 	}
@@ -642,7 +681,7 @@ func (c *Client) Version(ctx context.Context) (Version, error) {
 	c.connMu.Lock()
 	c.connMu.Lock()
 	if c.conn == nil {
 	if c.conn == nil {
 		c.connMu.Unlock()
 		c.connMu.Unlock()
-		return Version{}, errors.New("no grpc connection available")
+		return Version{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available")
 	}
 	}
 	c.connMu.Unlock()
 	c.connMu.Unlock()
 	response, err := c.VersionService().Version(ctx, &ptypes.Empty{})
 	response, err := c.VersionService().Version(ctx, &ptypes.Empty{})
@@ -655,6 +694,58 @@ func (c *Client) Version(ctx context.Context) (Version, error) {
 	}, nil
 	}, nil
 }
 }
 
 
+type ServerInfo struct {
+	UUID string
+}
+
+func (c *Client) Server(ctx context.Context) (ServerInfo, error) {
+	c.connMu.Lock()
+	if c.conn == nil {
+		c.connMu.Unlock()
+		return ServerInfo{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available")
+	}
+	c.connMu.Unlock()
+
+	response, err := c.IntrospectionService().Server(ctx, &types.Empty{})
+	if err != nil {
+		return ServerInfo{}, err
+	}
+	return ServerInfo{
+		UUID: response.UUID,
+	}, nil
+}
+
+func (c *Client) resolveSnapshotterName(ctx context.Context, name string) (string, error) {
+	if name == "" {
+		label, err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel)
+		if err != nil {
+			return "", err
+		}
+
+		if label != "" {
+			name = label
+		} else {
+			name = DefaultSnapshotter
+		}
+	}
+
+	return name, nil
+}
+
+func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) {
+	name, err := c.resolveSnapshotterName(ctx, name)
+	if err != nil {
+		return nil, err
+	}
+
+	s := c.SnapshotService(name)
+	if s == nil {
+		return nil, errors.Wrapf(errdefs.ErrNotFound, "snapshotter %s was not found", name)
+	}
+
+	return s, nil
+}
+
 // CheckRuntime returns true if the current runtime matches the expected
 // CheckRuntime returns true if the current runtime matches the expected
 // runtime. Providing various parts of the runtime schema will match those
 // runtime. Providing various parts of the runtime schema will match those
 // parts of the expected runtime
 // parts of the expected runtime

+ 17 - 9
vendor/github.com/containerd/containerd/client_opts.go

@@ -26,11 +26,12 @@ import (
 )
 )
 
 
 type clientOpts struct {
 type clientOpts struct {
-	defaultns      string
-	defaultRuntime string
-	services       *services
-	dialOptions    []grpc.DialOption
-	timeout        time.Duration
+	defaultns       string
+	defaultRuntime  string
+	defaultPlatform platforms.MatchComparer
+	services        *services
+	dialOptions     []grpc.DialOption
+	timeout         time.Duration
 }
 }
 
 
 // ClientOpt allows callers to set options on the containerd client
 // ClientOpt allows callers to set options on the containerd client
@@ -55,6 +56,14 @@ func WithDefaultRuntime(rt string) ClientOpt {
 	}
 	}
 }
 }
 
 
+// WithDefaultPlatform sets the default platform matcher on the client
+func WithDefaultPlatform(platform platforms.MatchComparer) ClientOpt {
+	return func(c *clientOpts) error {
+		c.defaultPlatform = platform
+		return nil
+	}
+}
+
 // WithDialOpts allows grpc.DialOptions to be set on the connection
 // WithDialOpts allows grpc.DialOptions to be set on the connection
 func WithDialOpts(opts []grpc.DialOption) ClientOpt {
 func WithDialOpts(opts []grpc.DialOption) ClientOpt {
 	return func(c *clientOpts) error {
 	return func(c *clientOpts) error {
@@ -195,11 +204,10 @@ func WithMaxConcurrentDownloads(max int) RemoteOpt {
 	}
 	}
 }
 }
 
 
-// WithAppendDistributionSourceLabel allows fetcher to add distribute source
-// label for each blob content, which doesn't work for legacy schema1.
-func WithAppendDistributionSourceLabel() RemoteOpt {
+// WithAllMetadata downloads all manifests and known-configuration files
+func WithAllMetadata() RemoteOpt {
 	return func(_ *Client, c *RemoteContext) error {
 	return func(_ *Client, c *RemoteContext) error {
-		c.AppendDistributionSourceLabel = true
+		c.AllMetadata = true
 		return nil
 		return nil
 	}
 	}
 }
 }

+ 32 - 9
vendor/github.com/containerd/containerd/container.go

@@ -25,6 +25,7 @@ import (
 
 
 	"github.com/containerd/containerd/api/services/tasks/v1"
 	"github.com/containerd/containerd/api/services/tasks/v1"
 	"github.com/containerd/containerd/api/types"
 	"github.com/containerd/containerd/api/types"
+	tasktypes "github.com/containerd/containerd/api/types/task"
 	"github.com/containerd/containerd/cio"
 	"github.com/containerd/containerd/cio"
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
@@ -49,7 +50,7 @@ type Container interface {
 	// ID identifies the container
 	// ID identifies the container
 	ID() string
 	ID() string
 	// Info returns the underlying container record type
 	// Info returns the underlying container record type
-	Info(context.Context) (containers.Container, error)
+	Info(context.Context, ...InfoOpts) (containers.Container, error)
 	// Delete removes the container
 	// Delete removes the container
 	Delete(context.Context, ...DeleteOpts) error
 	Delete(context.Context, ...DeleteOpts) error
 	// NewTask creates a new task based on the container metadata
 	// NewTask creates a new task based on the container metadata
@@ -80,16 +81,18 @@ type Container interface {
 
 
 func containerFromRecord(client *Client, c containers.Container) *container {
 func containerFromRecord(client *Client, c containers.Container) *container {
 	return &container{
 	return &container{
-		client: client,
-		id:     c.ID,
+		client:   client,
+		id:       c.ID,
+		metadata: c,
 	}
 	}
 }
 }
 
 
 var _ = (Container)(&container{})
 var _ = (Container)(&container{})
 
 
 type container struct {
 type container struct {
-	client *Client
-	id     string
+	client   *Client
+	id       string
+	metadata containers.Container
 }
 }
 
 
 // ID returns the container's unique id
 // ID returns the container's unique id
@@ -97,8 +100,22 @@ func (c *container) ID() string {
 	return c.id
 	return c.id
 }
 }
 
 
-func (c *container) Info(ctx context.Context) (containers.Container, error) {
-	return c.get(ctx)
+func (c *container) Info(ctx context.Context, opts ...InfoOpts) (containers.Container, error) {
+	i := &InfoConfig{
+		// default to refreshing the container's local metadata
+		Refresh: true,
+	}
+	for _, o := range opts {
+		o(i)
+	}
+	if i.Refresh {
+		metadata, err := c.get(ctx)
+		if err != nil {
+			return c.metadata, err
+		}
+		c.metadata = metadata
+	}
+	return c.metadata, nil
 }
 }
 
 
 func (c *container) Extensions(ctx context.Context) (map[string]prototypes.Any, error) {
 func (c *container) Extensions(ctx context.Context) (map[string]prototypes.Any, error) {
@@ -217,7 +234,11 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N
 		}
 		}
 
 
 		// get the rootfs from the snapshotter and add it to the request
 		// get the rootfs from the snapshotter and add it to the request
-		mounts, err := c.client.SnapshotService(r.Snapshotter).Mounts(ctx, r.SnapshotKey)
+		s, err := c.client.getSnapshotter(ctx, r.Snapshotter)
+		if err != nil {
+			return nil, err
+		}
+		mounts, err := s.Mounts(ctx, r.SnapshotKey)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -362,7 +383,9 @@ func (c *container) loadTask(ctx context.Context, ioAttach cio.Attach) (Task, er
 		return nil, err
 		return nil, err
 	}
 	}
 	var i cio.IO
 	var i cio.IO
-	if ioAttach != nil {
+	if ioAttach != nil && response.Process.Status != tasktypes.StatusUnknown {
+		// Do not attach IO for task in unknown state, because there
+		// are no fifo paths anyway.
 		if i, err = attachExistingIO(response, ioAttach); err != nil {
 		if i, err = attachExistingIO(response, ioAttach); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 61 - 27
vendor/github.com/containerd/containerd/container_opts.go

@@ -20,11 +20,8 @@ import (
 	"context"
 	"context"
 
 
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/containers"
-	"github.com/containerd/containerd/defaults"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
-	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/oci"
 	"github.com/containerd/containerd/oci"
-	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/snapshots"
 	"github.com/containerd/containerd/snapshots"
 	"github.com/containerd/typeurl"
 	"github.com/containerd/typeurl"
 	"github.com/gogo/protobuf/types"
 	"github.com/gogo/protobuf/types"
@@ -41,6 +38,15 @@ type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Co
 // UpdateContainerOpts allows the caller to set additional options when updating a container
 // UpdateContainerOpts allows the caller to set additional options when updating a container
 type UpdateContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error
 type UpdateContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error
 
 
+// InfoOpts controls how container metadata is fetched and returned
+type InfoOpts func(*InfoConfig)
+
+// InfoConfig specifies how container metadata is fetched
+type InfoConfig struct {
+	// Refresh will to a fetch of the latest container metadata
+	Refresh bool
+}
+
 // WithRuntime allows a user to specify the runtime name and additional options that should
 // WithRuntime allows a user to specify the runtime name and additional options that should
 // be used to create tasks for the container
 // be used to create tasks for the container
 func WithRuntime(name string, options interface{}) NewContainerOpts {
 func WithRuntime(name string, options interface{}) NewContainerOpts {
@@ -71,6 +77,14 @@ func WithImage(i Image) NewContainerOpts {
 	}
 	}
 }
 }
 
 
+// WithImageName allows setting the image name as the base for the container
+func WithImageName(n string) NewContainerOpts {
+	return func(ctx context.Context, _ *Client, c *containers.Container) error {
+		c.Image = n
+		return nil
+	}
+}
+
 // WithContainerLabels adds the provided labels to the container
 // WithContainerLabels adds the provided labels to the container
 func WithContainerLabels(labels map[string]string) NewContainerOpts {
 func WithContainerLabels(labels map[string]string) NewContainerOpts {
 	return func(_ context.Context, _ *Client, c *containers.Container) error {
 	return func(_ context.Context, _ *Client, c *containers.Container) error {
@@ -109,9 +123,17 @@ func WithSnapshotter(name string) NewContainerOpts {
 // WithSnapshot uses an existing root filesystem for the container
 // WithSnapshot uses an existing root filesystem for the container
 func WithSnapshot(id string) NewContainerOpts {
 func WithSnapshot(id string) NewContainerOpts {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
-		setSnapshotterIfEmpty(ctx, client, c)
 		// check that the snapshot exists, if not, fail on creation
 		// check that the snapshot exists, if not, fail on creation
-		if _, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, id); err != nil {
+		var err error
+		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		s, err := client.getSnapshotter(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		if _, err := s.Mounts(ctx, id); err != nil {
 			return err
 			return err
 		}
 		}
 		c.SnapshotKey = id
 		c.SnapshotKey = id
@@ -123,13 +145,21 @@ func WithSnapshot(id string) NewContainerOpts {
 // root filesystem in read-write mode
 // root filesystem in read-write mode
 func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts {
 func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
-		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
+		diffIDs, err := i.RootFS(ctx)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		setSnapshotterIfEmpty(ctx, client, c)
+
 		parent := identity.ChainID(diffIDs).String()
 		parent := identity.ChainID(diffIDs).String()
-		if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent, opts...); err != nil {
+		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		s, err := client.getSnapshotter(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		if _, err := s.Prepare(ctx, id, parent, opts...); err != nil {
 			return err
 			return err
 		}
 		}
 		c.SnapshotKey = id
 		c.SnapshotKey = id
@@ -144,7 +174,13 @@ func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Conta
 		if c.Snapshotter == "" {
 		if c.Snapshotter == "" {
 			return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot")
 			return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot")
 		}
 		}
-		return client.SnapshotService(c.Snapshotter).Remove(ctx, c.SnapshotKey)
+		s, err := client.getSnapshotter(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		if err := s.Remove(ctx, c.SnapshotKey); err != nil && !errdefs.IsNotFound(err) {
+			return err
+		}
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -153,13 +189,21 @@ func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Conta
 // root filesystem in read-only mode
 // root filesystem in read-only mode
 func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainerOpts {
 func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainerOpts {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
-		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
+		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		setSnapshotterIfEmpty(ctx, client, c)
+
 		parent := identity.ChainID(diffIDs).String()
 		parent := identity.ChainID(diffIDs).String()
-		if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent, opts...); err != nil {
+		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		s, err := client.getSnapshotter(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		if _, err := s.View(ctx, id, parent, opts...); err != nil {
 			return err
 			return err
 		}
 		}
 		c.SnapshotKey = id
 		c.SnapshotKey = id
@@ -168,21 +212,6 @@ func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainer
 	}
 	}
 }
 }
 
 
-func setSnapshotterIfEmpty(ctx context.Context, client *Client, c *containers.Container) {
-	if c.Snapshotter == "" {
-		defaultSnapshotter := DefaultSnapshotter
-		namespaceService := client.NamespaceService()
-		if ns, err := namespaces.NamespaceRequired(ctx); err == nil {
-			if labels, err := namespaceService.Labels(ctx, ns); err == nil {
-				if snapshotLabel, ok := labels[defaults.DefaultSnapshotterNSLabel]; ok {
-					defaultSnapshotter = snapshotLabel
-				}
-			}
-		}
-		c.Snapshotter = defaultSnapshotter
-	}
-}
-
 // WithContainerExtension appends extension data to the container object.
 // WithContainerExtension appends extension data to the container object.
 // Use this to decorate the container object with additional data for the client
 // Use this to decorate the container object with additional data for the client
 // integration.
 // integration.
@@ -235,3 +264,8 @@ func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts {
 		return err
 		return err
 	}
 	}
 }
 }
+
+// WithoutRefreshedMetadata will use the current metadata attached to the container object
+func WithoutRefreshedMetadata(i *InfoConfig) {
+	i.Refresh = false
+}

+ 11 - 7
vendor/github.com/containerd/containerd/container_opts_unix.go

@@ -28,7 +28,6 @@ import (
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/mount"
 	"github.com/containerd/containerd/mount"
-	"github.com/containerd/containerd/platforms"
 	"github.com/opencontainers/image-spec/identity"
 	"github.com/opencontainers/image-spec/identity"
 )
 )
 
 
@@ -45,18 +44,23 @@ func WithRemappedSnapshotView(id string, i Image, uid, gid uint32) NewContainerO
 
 
 func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool) NewContainerOpts {
 func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool) NewContainerOpts {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
 	return func(ctx context.Context, client *Client, c *containers.Container) error {
-		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
+		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
 
 
-		setSnapshotterIfEmpty(ctx, client, c)
-
 		var (
 		var (
-			snapshotter = client.SnapshotService(c.Snapshotter)
-			parent      = identity.ChainID(diffIDs).String()
-			usernsID    = fmt.Sprintf("%s-%d-%d", parent, uid, gid)
+			parent   = identity.ChainID(diffIDs).String()
+			usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid)
 		)
 		)
+		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
+		snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter)
+		if err != nil {
+			return err
+		}
 		if _, err := snapshotter.Stat(ctx, usernsID); err == nil {
 		if _, err := snapshotter.Stat(ctx, usernsID); err == nil {
 			if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil {
 			if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil {
 				c.SnapshotKey = id
 				c.SnapshotKey = id

+ 1 - 2
vendor/github.com/containerd/containerd/container_restore_opts.go

@@ -22,7 +22,6 @@ import (
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/images"
-	"github.com/containerd/containerd/platforms"
 	"github.com/gogo/protobuf/proto"
 	"github.com/gogo/protobuf/proto"
 	ptypes "github.com/gogo/protobuf/types"
 	ptypes "github.com/gogo/protobuf/types"
 	"github.com/opencontainers/image-spec/identity"
 	"github.com/opencontainers/image-spec/identity"
@@ -58,7 +57,7 @@ func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint
 			return err
 			return err
 		}
 		}
 
 
-		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
+		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 1 - 1
vendor/github.com/containerd/containerd/containers/containers.go

@@ -49,7 +49,7 @@ type Container struct {
 	// This property is required and immutable.
 	// This property is required and immutable.
 	Runtime RuntimeInfo
 	Runtime RuntimeInfo
 
 
-	// Spec should carry the the runtime specification used to implement the
+	// Spec should carry the runtime specification used to implement the
 	// container.
 	// container.
 	//
 	//
 	// This field is required but mutable.
 	// This field is required but mutable.

+ 30 - 1
vendor/github.com/containerd/containerd/content/helpers.go

@@ -55,7 +55,14 @@ func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) (
 
 
 	p := make([]byte, ra.Size())
 	p := make([]byte, ra.Size())
 
 
-	_, err = ra.ReadAt(p, 0)
+	n, err := ra.ReadAt(p, 0)
+	if err == io.EOF {
+		if int64(n) != ra.Size() {
+			err = io.ErrUnexpectedEOF
+		} else {
+			err = nil
+		}
+	}
 	return p, err
 	return p, err
 }
 }
 
 
@@ -162,6 +169,28 @@ func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
 	return err
 	return err
 }
 }
 
 
+// CopyReader copies to a writer from a given reader, returning
+// the number of bytes copied.
+// Note: if the writer has a non-zero offset, the total number
+// of bytes read may be greater than those copied if the reader
+// is not an io.Seeker.
+// This copy does not commit the writer.
+func CopyReader(cw Writer, r io.Reader) (int64, error) {
+	ws, err := cw.Status()
+	if err != nil {
+		return 0, errors.Wrap(err, "failed to get status")
+	}
+
+	if ws.Offset > 0 {
+		r, err = seekReader(r, ws.Offset, 0)
+		if err != nil {
+			return 0, errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
+		}
+	}
+
+	return copyWithBuffer(cw, r)
+}
+
 // seekReader attempts to seek the reader to the given offset, either by
 // seekReader attempts to seek the reader to the given offset, either by
 // resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
 // resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
 // up to the given offset.
 // up to the given offset.

+ 14 - 2
vendor/github.com/containerd/containerd/content/local/store.go

@@ -35,7 +35,6 @@ import (
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/log"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 
 
-	"github.com/containerd/continuity"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -661,6 +660,19 @@ func writeTimestampFile(p string, t time.Time) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	return atomicWrite(p, b, 0666)
+}
 
 
-	return continuity.AtomicWriteFile(p, b, 0666)
+func atomicWrite(path string, data []byte, mode os.FileMode) error {
+	tmp := fmt.Sprintf("%s.tmp", path)
+	f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode)
+	if err != nil {
+		return errors.Wrap(err, "create tmp file")
+	}
+	_, err = f.Write(data)
+	f.Close()
+	if err != nil {
+		return errors.Wrap(err, "write atomic data")
+	}
+	return os.Rename(tmp, path)
 }
 }

+ 1 - 1
vendor/github.com/containerd/containerd/contrib/nvidia/nvidia.go

@@ -52,7 +52,7 @@ const (
 	Display Capability = "display"
 	Display Capability = "display"
 )
 )
 
 
-// AllCaps returns the complete list of supported Nvidia capabilties.
+// AllCaps returns the complete list of supported Nvidia capabilities.
 func AllCaps() []Capability {
 func AllCaps() []Capability {
 	return []Capability{
 	return []Capability{
 		Compute,
 		Compute,

+ 0 - 2
vendor/github.com/containerd/containerd/contrib/seccomp/seccomp.go

@@ -1,5 +1,3 @@
-// +build linux
-
 /*
 /*
    Copyright The containerd Authors.
    Copyright The containerd Authors.
 
 

+ 5 - 3
vendor/github.com/containerd/containerd/contrib/seccomp/seccomp_default.go

@@ -20,7 +20,8 @@ package seccomp
 
 
 import (
 import (
 	"runtime"
 	"runtime"
-	"syscall"
+
+	"golang.org/x/sys/unix"
 
 
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/opencontainers/runtime-spec/specs-go"
 )
 )
@@ -311,6 +312,7 @@ func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
 				"sigaltstack",
 				"sigaltstack",
 				"signalfd",
 				"signalfd",
 				"signalfd4",
 				"signalfd4",
+				"sigprocmask",
 				"sigreturn",
 				"sigreturn",
 				"socket",
 				"socket",
 				"socketcall",
 				"socketcall",
@@ -555,7 +557,7 @@ func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
 				Args: []specs.LinuxSeccompArg{
 				Args: []specs.LinuxSeccompArg{
 					{
 					{
 						Index:    1,
 						Index:    1,
-						Value:    syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNET,
+						Value:    unix.CLONE_NEWNS | unix.CLONE_NEWUTS | unix.CLONE_NEWIPC | unix.CLONE_NEWUSER | unix.CLONE_NEWPID | unix.CLONE_NEWNET | unix.CLONE_NEWCGROUP,
 						ValueTwo: 0,
 						ValueTwo: 0,
 						Op:       specs.OpMaskedEqual,
 						Op:       specs.OpMaskedEqual,
 					},
 					},
@@ -570,7 +572,7 @@ func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
 				Args: []specs.LinuxSeccompArg{
 				Args: []specs.LinuxSeccompArg{
 					{
 					{
 						Index:    0,
 						Index:    0,
-						Value:    syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNET,
+						Value:    unix.CLONE_NEWNS | unix.CLONE_NEWUTS | unix.CLONE_NEWIPC | unix.CLONE_NEWUSER | unix.CLONE_NEWPID | unix.CLONE_NEWNET | unix.CLONE_NEWCGROUP,
 						ValueTwo: 0,
 						ValueTwo: 0,
 						Op:       specs.OpMaskedEqual,
 						Op:       specs.OpMaskedEqual,
 					},
 					},

+ 9 - 2
vendor/github.com/containerd/continuity/proto/gen.go → vendor/github.com/containerd/containerd/contrib/seccomp/seccomp_default_unsupported.go

@@ -1,3 +1,5 @@
+// +build !linux
+
 /*
 /*
    Copyright The containerd Authors.
    Copyright The containerd Authors.
 
 
@@ -14,6 +16,11 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proto
+package seccomp
+
+import specs "github.com/opencontainers/runtime-spec/specs-go"
 
 
-//go:generate protoc --go_out=. manifest.proto
+// DefaultProfile defines the whitelist for the default seccomp profile.
+func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
+	return &specs.LinuxSeccomp{}
+}

+ 2 - 2
vendor/github.com/containerd/containerd/defaults/defaults.go

@@ -23,10 +23,10 @@ const (
 	// DefaultMaxSendMsgSize defines the default maximum message size for
 	// DefaultMaxSendMsgSize defines the default maximum message size for
 	// sending protobufs passed over the GRPC API.
 	// sending protobufs passed over the GRPC API.
 	DefaultMaxSendMsgSize = 16 << 20
 	DefaultMaxSendMsgSize = 16 << 20
-	// DefaultRuntimeNSLabel defines the namespace label to check for
+	// DefaultRuntimeNSLabel defines the namespace label to check for the
 	// default runtime
 	// default runtime
 	DefaultRuntimeNSLabel = "containerd.io/defaults/runtime"
 	DefaultRuntimeNSLabel = "containerd.io/defaults/runtime"
-	// DefaultSnapshotterNSLabel defines the namespances label to check for
+	// DefaultSnapshotterNSLabel defines the namespace label to check for the
 	// default snapshotter
 	// default snapshotter
 	DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter"
 	DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter"
 )
 )

+ 2 - 0
vendor/github.com/containerd/containerd/defaults/defaults_unix.go

@@ -32,4 +32,6 @@ const (
 	// DefaultFIFODir is the default location used by client-side cio library
 	// DefaultFIFODir is the default location used by client-side cio library
 	// to store FIFOs.
 	// to store FIFOs.
 	DefaultFIFODir = "/run/containerd/fifo"
 	DefaultFIFODir = "/run/containerd/fifo"
+	// DefaultRuntime is the default linux runtime
+	DefaultRuntime = "io.containerd.runc.v2"
 )
 )

+ 2 - 0
vendor/github.com/containerd/containerd/defaults/defaults_windows.go

@@ -40,4 +40,6 @@ const (
 	// DefaultFIFODir is the default location used by client-side cio library
 	// DefaultFIFODir is the default location used by client-side cio library
 	// to store FIFOs. Unused on Windows.
 	// to store FIFOs. Unused on Windows.
 	DefaultFIFODir = ""
 	DefaultFIFODir = ""
+	// DefaultRuntime is the default windows runtime
+	DefaultRuntime = "io.containerd.runhcs.v1"
 )
 )

+ 10 - 3
vendor/github.com/containerd/containerd/diff.go

@@ -45,10 +45,17 @@ type diffRemote struct {
 	client diffapi.DiffClient
 	client diffapi.DiffClient
 }
 }
 
 
-func (r *diffRemote) Apply(ctx context.Context, diff ocispec.Descriptor, mounts []mount.Mount) (ocispec.Descriptor, error) {
+func (r *diffRemote) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (ocispec.Descriptor, error) {
+	var config diff.ApplyConfig
+	for _, opt := range opts {
+		if err := opt(ctx, desc, &config); err != nil {
+			return ocispec.Descriptor{}, err
+		}
+	}
 	req := &diffapi.ApplyRequest{
 	req := &diffapi.ApplyRequest{
-		Diff:   fromDescriptor(diff),
-		Mounts: fromMounts(mounts),
+		Diff:     fromDescriptor(desc),
+		Mounts:   fromMounts(mounts),
+		Payloads: config.ProcessorPayloads,
 	}
 	}
 	resp, err := r.client.Apply(ctx, req)
 	resp, err := r.client.Apply(ctx, req)
 	if err != nil {
 	if err != nil {

+ 19 - 1
vendor/github.com/containerd/containerd/diff/diff.go

@@ -20,6 +20,7 @@ import (
 	"context"
 	"context"
 
 
 	"github.com/containerd/containerd/mount"
 	"github.com/containerd/containerd/mount"
+	"github.com/gogo/protobuf/types"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 )
 )
 
 
@@ -51,6 +52,15 @@ type Comparer interface {
 	Compare(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error)
 	Compare(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error)
 }
 }
 
 
+// ApplyConfig is used to hold parameters needed for a apply operation
+type ApplyConfig struct {
+	// ProcessorPayloads specifies the payload sent to various processors
+	ProcessorPayloads map[string]*types.Any
+}
+
+// ApplyOpt is used to configure an Apply operation
+type ApplyOpt func(context.Context, ocispec.Descriptor, *ApplyConfig) error
+
 // Applier allows applying diffs between mounts
 // Applier allows applying diffs between mounts
 type Applier interface {
 type Applier interface {
 	// Apply applies the content referred to by the given descriptor to
 	// Apply applies the content referred to by the given descriptor to
@@ -58,7 +68,7 @@ type Applier interface {
 	// implementation and content descriptor. For example, in the common
 	// implementation and content descriptor. For example, in the common
 	// case the descriptor is a file system difference in tar format,
 	// case the descriptor is a file system difference in tar format,
 	// that tar would be applied on top of the mounts.
 	// that tar would be applied on top of the mounts.
-	Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error)
+	Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount, opts ...ApplyOpt) (ocispec.Descriptor, error)
 }
 }
 
 
 // WithMediaType sets the media type to use for creating the diff, without
 // WithMediaType sets the media type to use for creating the diff, without
@@ -87,3 +97,11 @@ func WithLabels(labels map[string]string) Opt {
 		return nil
 		return nil
 	}
 	}
 }
 }
+
+// WithPayloads sets the apply processor payloads to the config
+func WithPayloads(payloads map[string]*types.Any) ApplyOpt {
+	return func(_ context.Context, _ ocispec.Descriptor, c *ApplyConfig) error {
+		c.ProcessorPayloads = payloads
+		return nil
+	}
+}

+ 187 - 0
vendor/github.com/containerd/containerd/diff/stream.go

@@ -0,0 +1,187 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package diff
+
+import (
+	"context"
+	"io"
+	"os"
+
+	"github.com/containerd/containerd/archive/compression"
+	"github.com/containerd/containerd/images"
+	"github.com/gogo/protobuf/types"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/pkg/errors"
+)
+
+var (
+	handlers []Handler
+
+	// ErrNoProcessor is returned when no stream processor is available for a media-type
+	ErrNoProcessor = errors.New("no processor for media-type")
+)
+
+func init() {
+	// register the default compression handler
+	RegisterProcessor(compressedHandler)
+}
+
+// RegisterProcessor registers a stream processor for media-types
+func RegisterProcessor(handler Handler) {
+	handlers = append(handlers, handler)
+}
+
+// GetProcessor returns the processor for a media-type
+func GetProcessor(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) {
+	// reverse this list so that user configured handlers come up first
+	for i := len(handlers) - 1; i >= 0; i-- {
+		processor, ok := handlers[i](ctx, stream.MediaType())
+		if ok {
+			return processor(ctx, stream, payloads)
+		}
+	}
+	return nil, ErrNoProcessor
+}
+
+// Handler checks a media-type and initializes the processor
+type Handler func(ctx context.Context, mediaType string) (StreamProcessorInit, bool)
+
+// StaticHandler returns the processor init func for a static media-type
+func StaticHandler(expectedMediaType string, fn StreamProcessorInit) Handler {
+	return func(ctx context.Context, mediaType string) (StreamProcessorInit, bool) {
+		if mediaType == expectedMediaType {
+			return fn, true
+		}
+		return nil, false
+	}
+}
+
+// StreamProcessorInit returns the initialized stream processor
+type StreamProcessorInit func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error)
+
+// RawProcessor provides access to direct fd for processing
+type RawProcessor interface {
+	// File returns the fd for the read stream of the underlying processor
+	File() *os.File
+}
+
+// StreamProcessor handles processing a content stream and transforming it into a different media-type
+type StreamProcessor interface {
+	io.ReadCloser
+
+	// MediaType is the resulting media-type that the processor processes the stream into
+	MediaType() string
+}
+
+func compressedHandler(ctx context.Context, mediaType string) (StreamProcessorInit, bool) {
+	compressed, err := images.DiffCompression(ctx, mediaType)
+	if err != nil {
+		return nil, false
+	}
+	if compressed != "" {
+		return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) {
+			ds, err := compression.DecompressStream(stream)
+			if err != nil {
+				return nil, err
+			}
+
+			return &compressedProcessor{
+				rc: ds,
+			}, nil
+		}, true
+	}
+	return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) {
+		return &stdProcessor{
+			rc: stream,
+		}, nil
+	}, true
+}
+
+// NewProcessorChain initialized the root StreamProcessor
+func NewProcessorChain(mt string, r io.Reader) StreamProcessor {
+	return &processorChain{
+		mt: mt,
+		rc: r,
+	}
+}
+
+type processorChain struct {
+	mt string
+	rc io.Reader
+}
+
+func (c *processorChain) MediaType() string {
+	return c.mt
+}
+
+func (c *processorChain) Read(p []byte) (int, error) {
+	return c.rc.Read(p)
+}
+
+func (c *processorChain) Close() error {
+	return nil
+}
+
+type stdProcessor struct {
+	rc StreamProcessor
+}
+
+func (c *stdProcessor) MediaType() string {
+	return ocispec.MediaTypeImageLayer
+}
+
+func (c *stdProcessor) Read(p []byte) (int, error) {
+	return c.rc.Read(p)
+}
+
+func (c *stdProcessor) Close() error {
+	return nil
+}
+
+type compressedProcessor struct {
+	rc io.ReadCloser
+}
+
+func (c *compressedProcessor) MediaType() string {
+	return ocispec.MediaTypeImageLayer
+}
+
+func (c *compressedProcessor) Read(p []byte) (int, error) {
+	return c.rc.Read(p)
+}
+
+func (c *compressedProcessor) Close() error {
+	return c.rc.Close()
+}
+
+func BinaryHandler(id, returnsMediaType string, mediaTypes []string, path string, args []string) Handler {
+	set := make(map[string]struct{}, len(mediaTypes))
+	for _, m := range mediaTypes {
+		set[m] = struct{}{}
+	}
+	return func(_ context.Context, mediaType string) (StreamProcessorInit, bool) {
+		if _, ok := set[mediaType]; ok {
+			return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) {
+				payload := payloads[id]
+				return NewBinaryProcessor(ctx, mediaType, returnsMediaType, stream, path, args, payload)
+			}, true
+		}
+		return nil, false
+	}
+}
+
+const mediaTypeEnvVar = "STREAM_PROCESSOR_MEDIATYPE"

+ 146 - 0
vendor/github.com/containerd/containerd/diff/stream_unix.go

@@ -0,0 +1,146 @@
+// +build !windows
+
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package diff
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"sync"
+
+	"github.com/gogo/protobuf/proto"
+	"github.com/gogo/protobuf/types"
+	"github.com/pkg/errors"
+)
+
+// NewBinaryProcessor returns a binary processor for use with processing content streams
+func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args []string, payload *types.Any) (StreamProcessor, error) {
+	cmd := exec.CommandContext(ctx, name, args...)
+	cmd.Env = os.Environ()
+
+	var payloadC io.Closer
+	if payload != nil {
+		data, err := proto.Marshal(payload)
+		if err != nil {
+			return nil, err
+		}
+		r, w, err := os.Pipe()
+		if err != nil {
+			return nil, err
+		}
+		go func() {
+			io.Copy(w, bytes.NewReader(data))
+			w.Close()
+		}()
+
+		cmd.ExtraFiles = append(cmd.ExtraFiles, r)
+		payloadC = r
+	}
+	cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", mediaTypeEnvVar, imt))
+	var (
+		stdin  io.Reader
+		closer func() error
+		err    error
+	)
+	if f, ok := stream.(RawProcessor); ok {
+		stdin = f.File()
+		closer = f.File().Close
+	} else {
+		stdin = stream
+	}
+	cmd.Stdin = stdin
+	r, w, err := os.Pipe()
+	if err != nil {
+		return nil, err
+	}
+	cmd.Stdout = w
+
+	stderr := bytes.NewBuffer(nil)
+	cmd.Stderr = stderr
+
+	if err := cmd.Start(); err != nil {
+		return nil, err
+	}
+	p := &binaryProcessor{
+		cmd:    cmd,
+		r:      r,
+		mt:     rmt,
+		stderr: stderr,
+	}
+	go p.wait()
+
+	// close after start and dup
+	w.Close()
+	if closer != nil {
+		closer()
+	}
+	if payloadC != nil {
+		payloadC.Close()
+	}
+	return p, nil
+}
+
+type binaryProcessor struct {
+	cmd    *exec.Cmd
+	r      *os.File
+	mt     string
+	stderr *bytes.Buffer
+
+	mu  sync.Mutex
+	err error
+}
+
+func (c *binaryProcessor) Err() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.err
+}
+
+func (c *binaryProcessor) wait() {
+	if err := c.cmd.Wait(); err != nil {
+		if _, ok := err.(*exec.ExitError); ok {
+			c.mu.Lock()
+			c.err = errors.New(c.stderr.String())
+			c.mu.Unlock()
+		}
+	}
+}
+
+func (c *binaryProcessor) File() *os.File {
+	return c.r
+}
+
+func (c *binaryProcessor) MediaType() string {
+	return c.mt
+}
+
+func (c *binaryProcessor) Read(p []byte) (int, error) {
+	return c.r.Read(p)
+}
+
+func (c *binaryProcessor) Close() error {
+	err := c.r.Close()
+	if kerr := c.cmd.Process.Kill(); err == nil {
+		err = kerr
+	}
+	return err
+}

+ 165 - 0
vendor/github.com/containerd/containerd/diff/stream_windows.go

@@ -0,0 +1,165 @@
+// +build windows
+
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package diff
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"sync"
+
+	winio "github.com/Microsoft/go-winio"
+	"github.com/gogo/protobuf/proto"
+	"github.com/gogo/protobuf/types"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+)
+
+const processorPipe = "STREAM_PROCESSOR_PIPE"
+
+// NewBinaryProcessor returns a binary processor for use with processing content streams
+func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args []string, payload *types.Any) (StreamProcessor, error) {
+	cmd := exec.CommandContext(ctx, name, args...)
+	cmd.Env = os.Environ()
+
+	if payload != nil {
+		data, err := proto.Marshal(payload)
+		if err != nil {
+			return nil, err
+		}
+		up, err := getUiqPath()
+		if err != nil {
+			return nil, err
+		}
+		path := fmt.Sprintf("\\\\.\\pipe\\containerd-processor-%s-pipe", up)
+		l, err := winio.ListenPipe(path, nil)
+		if err != nil {
+			return nil, err
+		}
+		go func() {
+			defer l.Close()
+			conn, err := l.Accept()
+			if err != nil {
+				logrus.WithError(err).Error("accept npipe connection")
+				return
+			}
+			io.Copy(conn, bytes.NewReader(data))
+			conn.Close()
+		}()
+		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", processorPipe, path))
+	}
+	cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", mediaTypeEnvVar, imt))
+	var (
+		stdin  io.Reader
+		closer func() error
+		err    error
+	)
+	if f, ok := stream.(RawProcessor); ok {
+		stdin = f.File()
+		closer = f.File().Close
+	} else {
+		stdin = stream
+	}
+	cmd.Stdin = stdin
+	r, w, err := os.Pipe()
+	if err != nil {
+		return nil, err
+	}
+	cmd.Stdout = w
+	stderr := bytes.NewBuffer(nil)
+	cmd.Stderr = stderr
+
+	if err := cmd.Start(); err != nil {
+		return nil, err
+	}
+	p := &binaryProcessor{
+		cmd:    cmd,
+		r:      r,
+		mt:     rmt,
+		stderr: stderr,
+	}
+	go p.wait()
+
+	// close after start and dup
+	w.Close()
+	if closer != nil {
+		closer()
+	}
+	return p, nil
+}
+
+type binaryProcessor struct {
+	cmd    *exec.Cmd
+	r      *os.File
+	mt     string
+	stderr *bytes.Buffer
+
+	mu  sync.Mutex
+	err error
+}
+
+func (c *binaryProcessor) Err() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.err
+}
+
+func (c *binaryProcessor) wait() {
+	if err := c.cmd.Wait(); err != nil {
+		if _, ok := err.(*exec.ExitError); ok {
+			c.mu.Lock()
+			c.err = errors.New(c.stderr.String())
+			c.mu.Unlock()
+		}
+	}
+}
+
+func (c *binaryProcessor) File() *os.File {
+	return c.r
+}
+
+func (c *binaryProcessor) MediaType() string {
+	return c.mt
+}
+
+func (c *binaryProcessor) Read(p []byte) (int, error) {
+	return c.r.Read(p)
+}
+
+func (c *binaryProcessor) Close() error {
+	err := c.r.Close()
+	if kerr := c.cmd.Process.Kill(); err == nil {
+		err = kerr
+	}
+	return err
+}
+
+func getUiqPath() (string, error) {
+	dir, err := ioutil.TempDir("", "")
+	if err != nil {
+		return "", err
+	}
+	os.Remove(dir)
+	return filepath.Base(dir), nil
+}

+ 16 - 1
vendor/github.com/containerd/containerd/errdefs/errors.go

@@ -26,7 +26,11 @@
 // client-side errors to the correct types.
 // client-side errors to the correct types.
 package errdefs
 package errdefs
 
 
-import "github.com/pkg/errors"
+import (
+	"context"
+
+	"github.com/pkg/errors"
+)
 
 
 // Definitions of common error types used throughout containerd. All containerd
 // Definitions of common error types used throughout containerd. All containerd
 // errors returned by most packages will map into one of these errors classes.
 // errors returned by most packages will map into one of these errors classes.
@@ -76,3 +80,14 @@ func IsUnavailable(err error) bool {
 func IsNotImplemented(err error) bool {
 func IsNotImplemented(err error) bool {
 	return errors.Cause(err) == ErrNotImplemented
 	return errors.Cause(err) == ErrNotImplemented
 }
 }
+
+// IsCanceled returns true if the error is due to `context.Canceled`.
+func IsCanceled(err error) bool {
+	return errors.Cause(err) == context.Canceled
+}
+
+// IsDeadlineExceeded returns true if the error is due to
+// `context.DeadlineExceeded`.
+func IsDeadlineExceeded(err error) bool {
+	return errors.Cause(err) == context.DeadlineExceeded
+}

+ 9 - 0
vendor/github.com/containerd/containerd/errdefs/grpc.go

@@ -17,6 +17,7 @@
 package errdefs
 package errdefs
 
 
 import (
 import (
+	"context"
 	"strings"
 	"strings"
 
 
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -55,6 +56,10 @@ func ToGRPC(err error) error {
 		return status.Errorf(codes.Unavailable, err.Error())
 		return status.Errorf(codes.Unavailable, err.Error())
 	case IsNotImplemented(err):
 	case IsNotImplemented(err):
 		return status.Errorf(codes.Unimplemented, err.Error())
 		return status.Errorf(codes.Unimplemented, err.Error())
+	case IsCanceled(err):
+		return status.Errorf(codes.Canceled, err.Error())
+	case IsDeadlineExceeded(err):
+		return status.Errorf(codes.DeadlineExceeded, err.Error())
 	}
 	}
 
 
 	return err
 	return err
@@ -89,6 +94,10 @@ func FromGRPC(err error) error {
 		cls = ErrFailedPrecondition
 		cls = ErrFailedPrecondition
 	case codes.Unimplemented:
 	case codes.Unimplemented:
 		cls = ErrNotImplemented
 		cls = ErrNotImplemented
+	case codes.Canceled:
+		cls = context.Canceled
+	case codes.DeadlineExceeded:
+		cls = context.DeadlineExceeded
 	default:
 	default:
 		cls = ErrUnknown
 		cls = ErrUnknown
 	}
 	}

+ 1 - 1
vendor/github.com/containerd/containerd/events/exchange/exchange.go

@@ -50,7 +50,7 @@ var _ events.Publisher = &Exchange{}
 var _ events.Forwarder = &Exchange{}
 var _ events.Forwarder = &Exchange{}
 var _ events.Subscriber = &Exchange{}
 var _ events.Subscriber = &Exchange{}
 
 
-// Forward accepts an envelope to be direcly distributed on the exchange.
+// Forward accepts an envelope to be directly distributed on the exchange.
 //
 //
 // This is useful when an event is forwarded on behalf of another namespace or
 // This is useful when an event is forwarded on behalf of another namespace or
 // when the event is propagated on behalf of another publisher.
 // when the event is propagated on behalf of another publisher.

+ 6 - 20
vendor/github.com/containerd/containerd/export.go

@@ -20,26 +20,12 @@ import (
 	"context"
 	"context"
 	"io"
 	"io"
 
 
-	"github.com/containerd/containerd/images/oci"
-
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-	"github.com/pkg/errors"
+	"github.com/containerd/containerd/images/archive"
 )
 )
 
 
-// Export exports an image to a Tar stream.
-// OCI format is used by default.
-// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
-// TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream.
-func (c *Client) Export(ctx context.Context, desc ocispec.Descriptor, opts ...oci.V1ExporterOpt) (io.ReadCloser, error) {
-
-	exporter, err := oci.ResolveV1ExportOpt(opts...)
-	if err != nil {
-		return nil, err
-	}
-
-	pr, pw := io.Pipe()
-	go func() {
-		pw.CloseWithError(errors.Wrap(exporter.Export(ctx, c.ContentStore(), desc, pw), "export failed"))
-	}()
-	return pr, nil
+// Export exports images to a Tar stream.
+// The tar archive is in OCI format with a Docker compatible manifest
+// when a single target platform is given.
+func (c *Client) Export(ctx context.Context, w io.Writer, opts ...archive.ExportOpt) error {
+	return archive.Export(ctx, c.ContentStore(), w, opts...)
 }
 }

+ 7 - 0
vendor/github.com/containerd/containerd/gc/gc.go

@@ -30,6 +30,11 @@ import (
 // ResourceType represents type of resource at a node
 // ResourceType represents type of resource at a node
 type ResourceType uint8
 type ResourceType uint8
 
 
+// ResourceMax represents the max resource.
+// Upper bits are stripped out during the mark phase, allowing the upper 3 bits
+// to be used by the caller reference function.
+const ResourceMax = ResourceType(0x1F)
+
 // Node presents a resource which has a type and key,
 // Node presents a resource which has a type and key,
 // this node can be used to lookup other nodes.
 // this node can be used to lookup other nodes.
 type Node struct {
 type Node struct {
@@ -80,6 +85,8 @@ func Tricolor(roots []Node, refs func(ref Node) ([]Node, error)) (map[Node]struc
 			}
 			}
 		}
 		}
 
 
+		// strip bits above max resource type
+		id.Type = id.Type & ResourceMax
 		// mark as black when done
 		// mark as black when done
 		reachable[id] = struct{}{}
 		reachable[id] = struct{}{}
 	}
 	}

+ 174 - 9
vendor/github.com/containerd/containerd/image.go

@@ -19,16 +19,21 @@ package containerd
 import (
 import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
+	"strings"
+	"sync/atomic"
 
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/diff"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/rootfs"
 	"github.com/containerd/containerd/rootfs"
-	digest "github.com/opencontainers/go-digest"
+	"github.com/containerd/containerd/snapshots"
+	"github.com/opencontainers/go-digest"
 	"github.com/opencontainers/image-spec/identity"
 	"github.com/opencontainers/image-spec/identity"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
+	"golang.org/x/sync/semaphore"
 )
 )
 
 
 // Image describes an image used by containers
 // Image describes an image used by containers
@@ -40,11 +45,13 @@ type Image interface {
 	// Labels of the image
 	// Labels of the image
 	Labels() map[string]string
 	Labels() map[string]string
 	// Unpack unpacks the image's content into a snapshot
 	// Unpack unpacks the image's content into a snapshot
-	Unpack(context.Context, string) error
+	Unpack(context.Context, string, ...UnpackOpt) error
 	// RootFS returns the unpacked diffids that make up images rootfs.
 	// RootFS returns the unpacked diffids that make up images rootfs.
 	RootFS(ctx context.Context) ([]digest.Digest, error)
 	RootFS(ctx context.Context) ([]digest.Digest, error)
 	// Size returns the total size of the image's packed resources.
 	// Size returns the total size of the image's packed resources.
 	Size(ctx context.Context) (int64, error)
 	Size(ctx context.Context) (int64, error)
+	// Usage returns a usage calculation for the image.
+	Usage(context.Context, ...UsageOpt) (int64, error)
 	// Config descriptor for the image.
 	// Config descriptor for the image.
 	Config(ctx context.Context) (ocispec.Descriptor, error)
 	Config(ctx context.Context) (ocispec.Descriptor, error)
 	// IsUnpacked returns whether or not an image is unpacked.
 	// IsUnpacked returns whether or not an image is unpacked.
@@ -53,6 +60,49 @@ type Image interface {
 	ContentStore() content.Store
 	ContentStore() content.Store
 }
 }
 
 
+type usageOptions struct {
+	manifestLimit *int
+	manifestOnly  bool
+	snapshots     bool
+}
+
+// UsageOpt is used to configure the usage calculation
+type UsageOpt func(*usageOptions) error
+
+// WithUsageManifestLimit sets the limit to the number of manifests which will
+// be walked for usage. Setting this value to 0 will require all manifests to
+// be walked, returning ErrNotFound if manifests are missing.
+// NOTE: By default all manifests which exist will be walked
+// and any non-existent manifests and their subobjects will be ignored.
+func WithUsageManifestLimit(i int) UsageOpt {
+	// If 0 then don't filter any manifests
+	// By default limits to current platform
+	return func(o *usageOptions) error {
+		o.manifestLimit = &i
+		return nil
+	}
+}
+
+// WithSnapshotUsage will check for referenced snapshots from the image objects
+// and include the snapshot size in the total usage.
+func WithSnapshotUsage() UsageOpt {
+	return func(o *usageOptions) error {
+		o.snapshots = true
+		return nil
+	}
+}
+
+// WithManifestUsage is used to get the usage for an image based on what is
+// reported by the manifests rather than what exists in the content store.
+// NOTE: This function is best used with the manifest limit set to get a
+// consistent value, otherwise non-existent manifests will be excluded.
+func WithManifestUsage() UsageOpt {
+	return func(o *usageOptions) error {
+		o.manifestOnly = true
+		return nil
+	}
+}
+
 var _ = (Image)(&image{})
 var _ = (Image)(&image{})
 
 
 // NewImage returns a client image object from the metadata image
 // NewImage returns a client image object from the metadata image
@@ -60,7 +110,7 @@ func NewImage(client *Client, i images.Image) Image {
 	return &image{
 	return &image{
 		client:   client,
 		client:   client,
 		i:        i,
 		i:        i,
-		platform: platforms.Default(),
+		platform: client.platform,
 	}
 	}
 }
 }
 
 
@@ -98,8 +148,95 @@ func (i *image) RootFS(ctx context.Context) ([]digest.Digest, error) {
 }
 }
 
 
 func (i *image) Size(ctx context.Context) (int64, error) {
 func (i *image) Size(ctx context.Context) (int64, error) {
-	provider := i.client.ContentStore()
-	return i.i.Size(ctx, provider, i.platform)
+	return i.Usage(ctx, WithUsageManifestLimit(1), WithManifestUsage())
+}
+
+func (i *image) Usage(ctx context.Context, opts ...UsageOpt) (int64, error) {
+	var config usageOptions
+	for _, opt := range opts {
+		if err := opt(&config); err != nil {
+			return 0, err
+		}
+	}
+
+	var (
+		provider  = i.client.ContentStore()
+		handler   = images.ChildrenHandler(provider)
+		size      int64
+		mustExist bool
+	)
+
+	if config.manifestLimit != nil {
+		handler = images.LimitManifests(handler, i.platform, *config.manifestLimit)
+		mustExist = true
+	}
+
+	var wh images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+		var usage int64
+		children, err := handler(ctx, desc)
+		if err != nil {
+			if !errdefs.IsNotFound(err) || mustExist {
+				return nil, err
+			}
+			if !config.manifestOnly {
+				// Do not count size of non-existent objects
+				desc.Size = 0
+			}
+		} else if config.snapshots || !config.manifestOnly {
+			info, err := provider.Info(ctx, desc.Digest)
+			if err != nil {
+				if !errdefs.IsNotFound(err) {
+					return nil, err
+				}
+				if !config.manifestOnly {
+					// Do not count size of non-existent objects
+					desc.Size = 0
+				}
+			} else if info.Size > desc.Size {
+				// Count actual usage, Size may be unset or -1
+				desc.Size = info.Size
+			}
+
+			for k, v := range info.Labels {
+				const prefix = "containerd.io/gc.ref.snapshot."
+				if !strings.HasPrefix(k, prefix) {
+					continue
+				}
+
+				sn := i.client.SnapshotService(k[len(prefix):])
+				if sn == nil {
+					continue
+				}
+
+				u, err := sn.Usage(ctx, v)
+				if err != nil {
+					if !errdefs.IsNotFound(err) && !errdefs.IsInvalidArgument(err) {
+						return nil, err
+					}
+				} else {
+					usage += u.Size
+				}
+			}
+		}
+
+		// Ignore unknown sizes. Generally unknown sizes should
+		// never be set in manifests, however, the usage
+		// calculation does not need to enforce this.
+		if desc.Size >= 0 {
+			usage += desc.Size
+		}
+
+		atomic.AddInt64(&size, usage)
+
+		return children, nil
+	}
+
+	l := semaphore.NewWeighted(3)
+	if err := images.Dispatch(ctx, wh, l, i.i.Target); err != nil {
+		return 0, err
+	}
+
+	return size, nil
 }
 }
 
 
 func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) {
 func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) {
@@ -108,7 +245,10 @@ func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) {
 }
 }
 
 
 func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) {
 func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) {
-	sn := i.client.SnapshotService(snapshotterName)
+	sn, err := i.client.getSnapshotter(ctx, snapshotterName)
+	if err != nil {
+		return false, err
+	}
 	cs := i.client.ContentStore()
 	cs := i.client.ContentStore()
 
 
 	diffs, err := i.i.RootFS(ctx, cs, i.platform)
 	diffs, err := i.i.RootFS(ctx, cs, i.platform)
@@ -127,28 +267,53 @@ func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, e
 	return false, nil
 	return false, nil
 }
 }
 
 
-func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
+// UnpackConfig provides configuration for the unpack of an image
+type UnpackConfig struct {
+	// ApplyOpts for applying a diff to a snapshotter
+	ApplyOpts []diff.ApplyOpt
+	// SnapshotOpts for configuring a snapshotter
+	SnapshotOpts []snapshots.Opt
+}
+
+// UnpackOpt provides configuration for unpack
+type UnpackOpt func(context.Context, *UnpackConfig) error
+
+func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...UnpackOpt) error {
 	ctx, done, err := i.client.WithLease(ctx)
 	ctx, done, err := i.client.WithLease(ctx)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	defer done(ctx)
 	defer done(ctx)
 
 
+	var config UnpackConfig
+	for _, o := range opts {
+		if err := o(ctx, &config); err != nil {
+			return err
+		}
+	}
+
 	layers, err := i.getLayers(ctx, i.platform)
 	layers, err := i.getLayers(ctx, i.platform)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	var (
 	var (
-		sn = i.client.SnapshotService(snapshotterName)
 		a  = i.client.DiffService()
 		a  = i.client.DiffService()
 		cs = i.client.ContentStore()
 		cs = i.client.ContentStore()
 
 
 		chain    []digest.Digest
 		chain    []digest.Digest
 		unpacked bool
 		unpacked bool
 	)
 	)
+	snapshotterName, err = i.client.resolveSnapshotterName(ctx, snapshotterName)
+	if err != nil {
+		return err
+	}
+	sn, err := i.client.getSnapshotter(ctx, snapshotterName)
+	if err != nil {
+		return err
+	}
 	for _, layer := range layers {
 	for _, layer := range layers {
-		unpacked, err = rootfs.ApplyLayer(ctx, layer, chain, sn, a)
+		unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, config.SnapshotOpts, config.ApplyOpts)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 6 - 7
vendor/github.com/containerd/containerd/archive/tar_opts_unix.go → vendor/github.com/containerd/containerd/images/annotations.go

@@ -1,5 +1,3 @@
-// +build !windows
-
 /*
 /*
    Copyright The containerd Authors.
    Copyright The containerd Authors.
 
 
@@ -16,9 +14,10 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package archive
+package images
 
 
-// ApplyOptions provides additional options for an Apply operation
-type ApplyOptions struct {
-	Filter Filter // Filter tar headers
-}
+const (
+	// AnnotationImageName is an annotation on a Descriptor in an index.json
+	// containing the `Name` value as used by an `Image` struct
+	AnnotationImageName = "io.containerd.image.name"
+)

+ 468 - 0
vendor/github.com/containerd/containerd/images/archive/exporter.go

@@ -0,0 +1,468 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package archive
+
+import (
+	"archive/tar"
+	"context"
+	"encoding/json"
+	"io"
+	"path"
+	"sort"
+
+	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/errdefs"
+	"github.com/containerd/containerd/images"
+	"github.com/containerd/containerd/platforms"
+	digest "github.com/opencontainers/go-digest"
+	ocispecs "github.com/opencontainers/image-spec/specs-go"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/pkg/errors"
+)
+
+type exportOptions struct {
+	manifests          []ocispec.Descriptor
+	platform           platforms.MatchComparer
+	allPlatforms       bool
+	skipDockerManifest bool
+}
+
+// ExportOpt defines options for configuring exported descriptors
+type ExportOpt func(context.Context, *exportOptions) error
+
+// WithPlatform defines the platform to require manifest lists have
+// not exporting all platforms.
+// Additionally, platform is used to resolve image configs for
+// Docker v1.1, v1.2 format compatibility.
+func WithPlatform(p platforms.MatchComparer) ExportOpt {
+	return func(ctx context.Context, o *exportOptions) error {
+		o.platform = p
+		return nil
+	}
+}
+
+// WithAllPlatforms exports all manifests from a manifest list.
+// Missing content will fail the export.
+func WithAllPlatforms() ExportOpt {
+	return func(ctx context.Context, o *exportOptions) error {
+		o.allPlatforms = true
+		return nil
+	}
+}
+
+// WithSkipDockerManifest skips creation of the Docker compatible
+// manifest.json file.
+func WithSkipDockerManifest() ExportOpt {
+	return func(ctx context.Context, o *exportOptions) error {
+		o.skipDockerManifest = true
+		return nil
+	}
+}
+
+// WithImage adds the provided images to the exported archive.
+func WithImage(is images.Store, name string) ExportOpt {
+	return func(ctx context.Context, o *exportOptions) error {
+		img, err := is.Get(ctx, name)
+		if err != nil {
+			return err
+		}
+
+		img.Target.Annotations = addNameAnnotation(name, img.Target.Annotations)
+		o.manifests = append(o.manifests, img.Target)
+
+		return nil
+	}
+}
+
+// WithManifest adds a manifest to the exported archive.
+// When names are given they will be set on the manifest in the
+// exported archive, creating an index record for each name.
+// When no names are provided, it is up to caller to put name annotation to
+// on the manifest descriptor if needed.
+func WithManifest(manifest ocispec.Descriptor, names ...string) ExportOpt {
+	return func(ctx context.Context, o *exportOptions) error {
+		if len(names) == 0 {
+			o.manifests = append(o.manifests, manifest)
+		}
+		for _, name := range names {
+			mc := manifest
+			mc.Annotations = addNameAnnotation(name, manifest.Annotations)
+			o.manifests = append(o.manifests, mc)
+		}
+
+		return nil
+	}
+}
+
+func addNameAnnotation(name string, base map[string]string) map[string]string {
+	annotations := map[string]string{}
+	for k, v := range base {
+		annotations[k] = v
+	}
+
+	annotations[images.AnnotationImageName] = name
+	annotations[ocispec.AnnotationRefName] = ociReferenceName(name)
+
+	return annotations
+}
+
+// Export implements Exporter.
+func Export(ctx context.Context, store content.Provider, writer io.Writer, opts ...ExportOpt) error {
+	var eo exportOptions
+	for _, opt := range opts {
+		if err := opt(ctx, &eo); err != nil {
+			return err
+		}
+	}
+
+	records := []tarRecord{
+		ociLayoutFile(""),
+		ociIndexRecord(eo.manifests),
+	}
+
+	algorithms := map[string]struct{}{}
+	dManifests := map[digest.Digest]*exportManifest{}
+	resolvedIndex := map[digest.Digest]digest.Digest{}
+	for _, desc := range eo.manifests {
+		switch desc.MediaType {
+		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+			mt, ok := dManifests[desc.Digest]
+			if !ok {
+				// TODO(containerd): Skip if already added
+				r, err := getRecords(ctx, store, desc, algorithms)
+				if err != nil {
+					return err
+				}
+				records = append(records, r...)
+
+				mt = &exportManifest{
+					manifest: desc,
+				}
+				dManifests[desc.Digest] = mt
+			}
+
+			name := desc.Annotations[images.AnnotationImageName]
+			if name != "" && !eo.skipDockerManifest {
+				mt.names = append(mt.names, name)
+			}
+		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+			d, ok := resolvedIndex[desc.Digest]
+			if !ok {
+				records = append(records, blobRecord(store, desc))
+
+				p, err := content.ReadBlob(ctx, store, desc)
+				if err != nil {
+					return err
+				}
+
+				var index ocispec.Index
+				if err := json.Unmarshal(p, &index); err != nil {
+					return err
+				}
+
+				var manifests []ocispec.Descriptor
+				for _, m := range index.Manifests {
+					if eo.platform != nil {
+						if m.Platform == nil || eo.platform.Match(*m.Platform) {
+							manifests = append(manifests, m)
+						} else if !eo.allPlatforms {
+							continue
+						}
+					}
+
+					r, err := getRecords(ctx, store, m, algorithms)
+					if err != nil {
+						return err
+					}
+
+					records = append(records, r...)
+				}
+
+				if !eo.skipDockerManifest {
+					if len(manifests) >= 1 {
+						if len(manifests) > 1 {
+							sort.SliceStable(manifests, func(i, j int) bool {
+								if manifests[i].Platform == nil {
+									return false
+								}
+								if manifests[j].Platform == nil {
+									return true
+								}
+								return eo.platform.Less(*manifests[i].Platform, *manifests[j].Platform)
+							})
+						}
+						d = manifests[0].Digest
+						dManifests[d] = &exportManifest{
+							manifest: manifests[0],
+						}
+					} else if eo.platform != nil {
+						return errors.Wrap(errdefs.ErrNotFound, "no manifest found for platform")
+					}
+				}
+				resolvedIndex[desc.Digest] = d
+			}
+			if d != "" {
+				if name := desc.Annotations[images.AnnotationImageName]; name != "" {
+					mt := dManifests[d]
+					mt.names = append(mt.names, name)
+				}
+
+			}
+		default:
+			return errors.Wrap(errdefs.ErrInvalidArgument, "only manifests may be exported")
+		}
+	}
+
+	if len(dManifests) > 0 {
+		tr, err := manifestsRecord(ctx, store, dManifests)
+		if err != nil {
+			return errors.Wrap(err, "unable to create manifests file")
+		}
+
+		records = append(records, tr)
+	}
+
+	if len(algorithms) > 0 {
+		records = append(records, directoryRecord("blobs/", 0755))
+		for alg := range algorithms {
+			records = append(records, directoryRecord("blobs/"+alg+"/", 0755))
+		}
+	}
+
+	tw := tar.NewWriter(writer)
+	defer tw.Close()
+	return writeTar(ctx, tw, records)
+}
+
+func getRecords(ctx context.Context, store content.Provider, desc ocispec.Descriptor, algorithms map[string]struct{}) ([]tarRecord, error) {
+	var records []tarRecord
+	exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+		records = append(records, blobRecord(store, desc))
+		algorithms[desc.Digest.Algorithm().String()] = struct{}{}
+		return nil, nil
+	}
+
+	childrenHandler := images.ChildrenHandler(store)
+
+	handlers := images.Handlers(
+		childrenHandler,
+		images.HandlerFunc(exportHandler),
+	)
+
+	// Walk sequentially since the number of fetchs is likely one and doing in
+	// parallel requires locking the export handler
+	if err := images.Walk(ctx, handlers, desc); err != nil {
+		return nil, err
+	}
+
+	return records, nil
+}
+
+type tarRecord struct {
+	Header *tar.Header
+	CopyTo func(context.Context, io.Writer) (int64, error)
+}
+
+func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
+	path := path.Join("blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
+	return tarRecord{
+		Header: &tar.Header{
+			Name:     path,
+			Mode:     0444,
+			Size:     desc.Size,
+			Typeflag: tar.TypeReg,
+		},
+		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
+			r, err := cs.ReaderAt(ctx, desc)
+			if err != nil {
+				return 0, errors.Wrap(err, "failed to get reader")
+			}
+			defer r.Close()
+
+			// Verify digest
+			dgstr := desc.Digest.Algorithm().Digester()
+
+			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
+			if err != nil {
+				return 0, errors.Wrap(err, "failed to copy to tar")
+			}
+			if dgstr.Digest() != desc.Digest {
+				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
+			}
+			return n, nil
+		},
+	}
+}
+
+func directoryRecord(name string, mode int64) tarRecord {
+	return tarRecord{
+		Header: &tar.Header{
+			Name:     name,
+			Mode:     mode,
+			Typeflag: tar.TypeDir,
+		},
+	}
+}
+
+func ociLayoutFile(version string) tarRecord {
+	if version == "" {
+		version = ocispec.ImageLayoutVersion
+	}
+	layout := ocispec.ImageLayout{
+		Version: version,
+	}
+
+	b, err := json.Marshal(layout)
+	if err != nil {
+		panic(err)
+	}
+
+	return tarRecord{
+		Header: &tar.Header{
+			Name:     ocispec.ImageLayoutFile,
+			Mode:     0444,
+			Size:     int64(len(b)),
+			Typeflag: tar.TypeReg,
+		},
+		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
+			n, err := w.Write(b)
+			return int64(n), err
+		},
+	}
+
+}
+
+func ociIndexRecord(manifests []ocispec.Descriptor) tarRecord {
+	index := ocispec.Index{
+		Versioned: ocispecs.Versioned{
+			SchemaVersion: 2,
+		},
+		Manifests: manifests,
+	}
+
+	b, err := json.Marshal(index)
+	if err != nil {
+		panic(err)
+	}
+
+	return tarRecord{
+		Header: &tar.Header{
+			Name:     "index.json",
+			Mode:     0644,
+			Size:     int64(len(b)),
+			Typeflag: tar.TypeReg,
+		},
+		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
+			n, err := w.Write(b)
+			return int64(n), err
+		},
+	}
+}
+
+type exportManifest struct {
+	manifest ocispec.Descriptor
+	names    []string
+}
+
+func manifestsRecord(ctx context.Context, store content.Provider, manifests map[digest.Digest]*exportManifest) (tarRecord, error) {
+	mfsts := make([]struct {
+		Config   string
+		RepoTags []string
+		Layers   []string
+	}, len(manifests))
+
+	var i int
+	for _, m := range manifests {
+		p, err := content.ReadBlob(ctx, store, m.manifest)
+		if err != nil {
+			return tarRecord{}, err
+		}
+
+		var manifest ocispec.Manifest
+		if err := json.Unmarshal(p, &manifest); err != nil {
+			return tarRecord{}, err
+		}
+		if err := manifest.Config.Digest.Validate(); err != nil {
+			return tarRecord{}, errors.Wrapf(err, "invalid manifest %q", m.manifest.Digest)
+		}
+
+		dgst := manifest.Config.Digest
+		mfsts[i].Config = path.Join("blobs", dgst.Algorithm().String(), dgst.Encoded())
+		for _, l := range manifest.Layers {
+			path := path.Join("blobs", l.Digest.Algorithm().String(), l.Digest.Encoded())
+			mfsts[i].Layers = append(mfsts[i].Layers, path)
+		}
+
+		for _, name := range m.names {
+			nname, err := familiarizeReference(name)
+			if err != nil {
+				return tarRecord{}, err
+			}
+
+			mfsts[i].RepoTags = append(mfsts[i].RepoTags, nname)
+		}
+
+		i++
+	}
+
+	b, err := json.Marshal(mfsts)
+	if err != nil {
+		return tarRecord{}, err
+	}
+
+	return tarRecord{
+		Header: &tar.Header{
+			Name:     "manifest.json",
+			Mode:     0644,
+			Size:     int64(len(b)),
+			Typeflag: tar.TypeReg,
+		},
+		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
+			n, err := w.Write(b)
+			return int64(n), err
+		},
+	}, nil
+}
+
+func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error {
+	sort.Slice(records, func(i, j int) bool {
+		return records[i].Header.Name < records[j].Header.Name
+	})
+
+	var last string
+	for _, record := range records {
+		if record.Header.Name == last {
+			continue
+		}
+		last = record.Header.Name
+		if err := tw.WriteHeader(record.Header); err != nil {
+			return err
+		}
+		if record.CopyTo != nil {
+			n, err := record.CopyTo(ctx, tw)
+			if err != nil {
+				return err
+			}
+			if n != record.Header.Size {
+				return errors.Errorf("unexpected copy size for %s", record.Header.Name)
+			}
+		} else if record.Header.Size > 0 {
+			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
+		}
+	}
+	return nil
+}

+ 133 - 21
vendor/github.com/containerd/containerd/images/archive/importer.go

@@ -22,12 +22,14 @@ import (
 	"bytes"
 	"bytes"
 	"context"
 	"context"
 	"encoding/json"
 	"encoding/json"
+	"fmt"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"path"
 	"path"
 
 
 	"github.com/containerd/containerd/archive/compression"
 	"github.com/containerd/containerd/archive/compression"
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/log"
 	digest "github.com/opencontainers/go-digest"
 	digest "github.com/opencontainers/go-digest"
@@ -36,6 +38,22 @@ import (
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
 
 
+type importOpts struct {
+	compress bool
+}
+
+// ImportOpt is an option for importing an OCI index
+type ImportOpt func(*importOpts) error
+
+// WithImportCompression compresses uncompressed layers on import.
+// This is used for import formats which do not include the manifest.
+func WithImportCompression() ImportOpt {
+	return func(io *importOpts) error {
+		io.compress = true
+		return nil
+	}
+}
+
 // ImportIndex imports an index from a tar archive image bundle
 // ImportIndex imports an index from a tar archive image bundle
 // - implements Docker v1.1, v1.2 and OCI v1.
 // - implements Docker v1.1, v1.2 and OCI v1.
 // - prefers OCI v1 when provided
 // - prefers OCI v1 when provided
@@ -43,8 +61,7 @@ import (
 // - normalizes Docker references and adds as OCI ref name
 // - normalizes Docker references and adds as OCI ref name
 //      e.g. alpine:latest -> docker.io/library/alpine:latest
 //      e.g. alpine:latest -> docker.io/library/alpine:latest
 // - existing OCI reference names are untouched
 // - existing OCI reference names are untouched
-// - TODO: support option to compress layers on ingest
-func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (ocispec.Descriptor, error) {
+func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opts ...ImportOpt) (ocispec.Descriptor, error) {
 	var (
 	var (
 		tr = tar.NewReader(reader)
 		tr = tar.NewReader(reader)
 
 
@@ -56,7 +73,15 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc
 		}
 		}
 		symlinks = make(map[string]string)
 		symlinks = make(map[string]string)
 		blobs    = make(map[string]ocispec.Descriptor)
 		blobs    = make(map[string]ocispec.Descriptor)
+		iopts    importOpts
 	)
 	)
+
+	for _, o := range opts {
+		if err := o(&iopts); err != nil {
+			return ocispec.Descriptor{}, err
+		}
+	}
+
 	for {
 	for {
 		hdr, err := tr.Next()
 		hdr, err := tr.Next()
 		if err == io.EOF {
 		if err == io.EOF {
@@ -99,7 +124,7 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc
 	}
 	}
 
 
 	// If OCI layout was given, interpret the tar as an OCI layout.
 	// If OCI layout was given, interpret the tar as an OCI layout.
-	// When not provided, the layout of the tar will be interpretted
+	// When not provided, the layout of the tar will be interpreted
 	// as Docker v1.1 or v1.2.
 	// as Docker v1.1 or v1.2.
 	if ociLayout.Version != "" {
 	if ociLayout.Version != "" {
 		if ociLayout.Version != ocispec.ImageLayoutVersion {
 		if ociLayout.Version != ocispec.ImageLayoutVersion {
@@ -137,19 +162,23 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc
 		if !ok {
 		if !ok {
 			return ocispec.Descriptor{}, errors.Errorf("image config %q not found", mfst.Config)
 			return ocispec.Descriptor{}, errors.Errorf("image config %q not found", mfst.Config)
 		}
 		}
-		config.MediaType = ocispec.MediaTypeImageConfig
+		config.MediaType = images.MediaTypeDockerSchema2Config
 
 
-		layers, err := resolveLayers(ctx, store, mfst.Layers, blobs)
+		layers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress)
 		if err != nil {
 		if err != nil {
 			return ocispec.Descriptor{}, errors.Wrap(err, "failed to resolve layers")
 			return ocispec.Descriptor{}, errors.Wrap(err, "failed to resolve layers")
 		}
 		}
 
 
-		manifest := ocispec.Manifest{
-			Versioned: specs.Versioned{
-				SchemaVersion: 2,
-			},
-			Config: config,
-			Layers: layers,
+		manifest := struct {
+			SchemaVersion int                  `json:"schemaVersion"`
+			MediaType     string               `json:"mediaType"`
+			Config        ocispec.Descriptor   `json:"config"`
+			Layers        []ocispec.Descriptor `json:"layers"`
+		}{
+			SchemaVersion: 2,
+			MediaType:     images.MediaTypeDockerSchema2Manifest,
+			Config:        config,
+			Layers:        layers,
 		}
 		}
 
 
 		desc, err := writeManifest(ctx, store, manifest, ocispec.MediaTypeImageManifest)
 		desc, err := writeManifest(ctx, store, manifest, ocispec.MediaTypeImageManifest)
@@ -181,7 +210,8 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc
 				}
 				}
 
 
 				mfstdesc.Annotations = map[string]string{
 				mfstdesc.Annotations = map[string]string{
-					ocispec.AnnotationRefName: normalized,
+					images.AnnotationImageName: normalized,
+					ocispec.AnnotationRefName:  ociReferenceName(normalized),
 				}
 				}
 
 
 				idx.Manifests = append(idx.Manifests, mfstdesc)
 				idx.Manifests = append(idx.Manifests, mfstdesc)
@@ -210,36 +240,118 @@ func onUntarBlob(ctx context.Context, r io.Reader, store content.Ingester, size
 	return dgstr.Digest(), nil
 	return dgstr.Digest(), nil
 }
 }
 
 
-func resolveLayers(ctx context.Context, store content.Store, layerFiles []string, blobs map[string]ocispec.Descriptor) ([]ocispec.Descriptor, error) {
-	var layers []ocispec.Descriptor
-	for _, f := range layerFiles {
+func resolveLayers(ctx context.Context, store content.Store, layerFiles []string, blobs map[string]ocispec.Descriptor, compress bool) ([]ocispec.Descriptor, error) {
+	layers := make([]ocispec.Descriptor, len(layerFiles))
+	descs := map[digest.Digest]*ocispec.Descriptor{}
+	filters := []string{}
+	for i, f := range layerFiles {
 		desc, ok := blobs[f]
 		desc, ok := blobs[f]
 		if !ok {
 		if !ok {
 			return nil, errors.Errorf("layer %q not found", f)
 			return nil, errors.Errorf("layer %q not found", f)
 		}
 		}
+		layers[i] = desc
+		descs[desc.Digest] = &layers[i]
+		filters = append(filters, "labels.\"containerd.io/uncompressed\"=="+desc.Digest.String())
+	}
 
 
+	err := store.Walk(ctx, func(info content.Info) error {
+		dgst, ok := info.Labels["containerd.io/uncompressed"]
+		if ok {
+			desc := descs[digest.Digest(dgst)]
+			if desc != nil {
+				desc.MediaType = images.MediaTypeDockerSchema2LayerGzip
+				desc.Digest = info.Digest
+				desc.Size = info.Size
+			}
+		}
+		return nil
+	}, filters...)
+	if err != nil {
+		return nil, errors.Wrap(err, "failure checking for compressed blobs")
+	}
+
+	for i, desc := range layers {
+		if desc.MediaType != "" {
+			continue
+		}
 		// Open blob, resolve media type
 		// Open blob, resolve media type
 		ra, err := store.ReaderAt(ctx, desc)
 		ra, err := store.ReaderAt(ctx, desc)
 		if err != nil {
 		if err != nil {
-			return nil, errors.Wrapf(err, "failed to open %q (%s)", f, desc.Digest)
+			return nil, errors.Wrapf(err, "failed to open %q (%s)", layerFiles[i], desc.Digest)
 		}
 		}
 		s, err := compression.DecompressStream(content.NewReader(ra))
 		s, err := compression.DecompressStream(content.NewReader(ra))
 		if err != nil {
 		if err != nil {
-			return nil, errors.Wrapf(err, "failed to detect compression for %q", f)
+			return nil, errors.Wrapf(err, "failed to detect compression for %q", layerFiles[i])
 		}
 		}
 		if s.GetCompression() == compression.Uncompressed {
 		if s.GetCompression() == compression.Uncompressed {
-			// TODO: Support compressing and writing back to content store
-			desc.MediaType = ocispec.MediaTypeImageLayer
+			if compress {
+				ref := fmt.Sprintf("compress-blob-%s-%s", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
+				labels := map[string]string{
+					"containerd.io/uncompressed": desc.Digest.String(),
+				}
+				layers[i], err = compressBlob(ctx, store, s, ref, content.WithLabels(labels))
+				if err != nil {
+					s.Close()
+					return nil, err
+				}
+				layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip
+			} else {
+				layers[i].MediaType = images.MediaTypeDockerSchema2Layer
+			}
 		} else {
 		} else {
-			desc.MediaType = ocispec.MediaTypeImageLayerGzip
+			layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip
 		}
 		}
 		s.Close()
 		s.Close()
 
 
-		layers = append(layers, desc)
 	}
 	}
 	return layers, nil
 	return layers, nil
 }
 }
 
 
+func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string, opts ...content.Opt) (desc ocispec.Descriptor, err error) {
+	w, err := content.OpenWriter(ctx, cs, content.WithRef(ref))
+	if err != nil {
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to open writer")
+	}
+
+	defer func() {
+		w.Close()
+		if err != nil {
+			cs.Abort(ctx, ref)
+		}
+	}()
+	if err := w.Truncate(0); err != nil {
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to truncate writer")
+	}
+
+	cw, err := compression.CompressStream(w, compression.Gzip)
+	if err != nil {
+		return ocispec.Descriptor{}, err
+	}
+
+	if _, err := io.Copy(cw, r); err != nil {
+		return ocispec.Descriptor{}, err
+	}
+	if err := cw.Close(); err != nil {
+		return ocispec.Descriptor{}, err
+	}
+
+	cst, err := w.Status()
+	if err != nil {
+		return ocispec.Descriptor{}, errors.Wrap(err, "failed to get writer status")
+	}
+
+	desc.Digest = w.Digest()
+	desc.Size = cst.Offset
+
+	if err := w.Commit(ctx, desc.Size, desc.Digest, opts...); err != nil {
+		if !errdefs.IsAlreadyExists(err) {
+			return ocispec.Descriptor{}, errors.Wrap(err, "failed to commit")
+		}
+	}
+
+	return desc, nil
+}
+
 func writeManifest(ctx context.Context, cs content.Ingester, manifest interface{}, mediaType string) (ocispec.Descriptor, error) {
 func writeManifest(ctx context.Context, cs content.Ingester, manifest interface{}, mediaType string) (ocispec.Descriptor, error) {
 	manifestBytes, err := json.Marshal(manifest)
 	manifestBytes, err := json.Marshal(manifest)
 	if err != nil {
 	if err != nil {

+ 28 - 2
vendor/github.com/containerd/containerd/images/archive/reference.go

@@ -19,7 +19,8 @@ package archive
 import (
 import (
 	"strings"
 	"strings"
 
 
-	"github.com/docker/distribution/reference"
+	"github.com/containerd/containerd/reference"
+	distref "github.com/docker/distribution/reference"
 	"github.com/opencontainers/go-digest"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
@@ -69,7 +70,7 @@ func isImagePrefix(s, prefix string) bool {
 
 
 func normalizeReference(ref string) (string, error) {
 func normalizeReference(ref string) (string, error) {
 	// TODO: Replace this function to not depend on reference package
 	// TODO: Replace this function to not depend on reference package
-	normalized, err := reference.ParseDockerRef(ref)
+	normalized, err := distref.ParseDockerRef(ref)
 	if err != nil {
 	if err != nil {
 		return "", errors.Wrapf(err, "normalize image ref %q", ref)
 		return "", errors.Wrapf(err, "normalize image ref %q", ref)
 	}
 	}
@@ -77,6 +78,31 @@ func normalizeReference(ref string) (string, error) {
 	return normalized.String(), nil
 	return normalized.String(), nil
 }
 }
 
 
+func familiarizeReference(ref string) (string, error) {
+	named, err := distref.ParseNormalizedNamed(ref)
+	if err != nil {
+		return "", errors.Wrapf(err, "failed to parse %q", ref)
+	}
+	named = distref.TagNameOnly(named)
+
+	return distref.FamiliarString(named), nil
+}
+
+func ociReferenceName(name string) string {
+	// OCI defines the reference name as only a tag excluding the
+	// repository. The containerd annotation contains the full image name
+	// since the tag is insufficient for correctly naming and referring to an
+	// image
+	var ociRef string
+	if spec, err := reference.Parse(name); err == nil {
+		ociRef = spec.Object
+	} else {
+		ociRef = name
+	}
+
+	return ociRef
+}
+
 // DigestTranslator creates a digest reference by adding the
 // DigestTranslator creates a digest reference by adding the
 // digest to an image name
 // digest to an image name
 func DigestTranslator(prefix string) func(digest.Digest) string {
 func DigestTranslator(prefix string) func(digest.Digest) string {

+ 4 - 3
vendor/github.com/containerd/containerd/images/handlers.go

@@ -117,7 +117,7 @@ func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) err
 //
 //
 // If any handler returns an error, the dispatch session will be canceled.
 // If any handler returns an error, the dispatch session will be canceled.
 func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
 func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
-	eg, ctx := errgroup.WithContext(ctx)
+	eg, ctx2 := errgroup.WithContext(ctx)
 	for _, desc := range descs {
 	for _, desc := range descs {
 		desc := desc
 		desc := desc
 
 
@@ -126,10 +126,11 @@ func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted,
 				return err
 				return err
 			}
 			}
 		}
 		}
+
 		eg.Go(func() error {
 		eg.Go(func() error {
 			desc := desc
 			desc := desc
 
 
-			children, err := handler.Handle(ctx, desc)
+			children, err := handler.Handle(ctx2, desc)
 			if limiter != nil {
 			if limiter != nil {
 				limiter.Release(1)
 				limiter.Release(1)
 			}
 			}
@@ -141,7 +142,7 @@ func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted,
 			}
 			}
 
 
 			if len(children) > 0 {
 			if len(children) > 0 {
-				return Dispatch(ctx, handler, limiter, children...)
+				return Dispatch(ctx2, handler, limiter, children...)
 			}
 			}
 
 
 			return nil
 			return nil

+ 19 - 41
vendor/github.com/containerd/containerd/images/image.go

@@ -20,7 +20,6 @@ import (
 	"context"
 	"context"
 	"encoding/json"
 	"encoding/json"
 	"sort"
 	"sort"
-	"strings"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
@@ -119,7 +118,7 @@ func (image *Image) Size(ctx context.Context, provider content.Provider, platfor
 		}
 		}
 		size += desc.Size
 		size += desc.Size
 		return nil, nil
 		return nil, nil
-	}), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target)
+	}), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target)
 }
 }
 
 
 type platformManifest struct {
 type platformManifest struct {
@@ -142,6 +141,7 @@ type platformManifest struct {
 // this direction because this abstraction is not needed.`
 // this direction because this abstraction is not needed.`
 func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) {
 func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) {
 	var (
 	var (
+		limit    = 1
 		m        []platformManifest
 		m        []platformManifest
 		wasIndex bool
 		wasIndex bool
 	)
 	)
@@ -210,10 +210,22 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
 				}
 				}
 			}
 			}
 
 
+			sort.SliceStable(descs, func(i, j int) bool {
+				if descs[i].Platform == nil {
+					return false
+				}
+				if descs[j].Platform == nil {
+					return true
+				}
+				return platform.Less(*descs[i].Platform, *descs[j].Platform)
+			})
+
 			wasIndex = true
 			wasIndex = true
 
 
+			if len(descs) > limit {
+				return descs[:limit], nil
+			}
 			return descs, nil
 			return descs, nil
-
 		}
 		}
 		return nil, errors.Wrapf(errdefs.ErrNotFound, "unexpected media type %v for %v", desc.MediaType, desc.Digest)
 		return nil, errors.Wrapf(errdefs.ErrNotFound, "unexpected media type %v for %v", desc.MediaType, desc.Digest)
 	}), image); err != nil {
 	}), image); err != nil {
@@ -227,17 +239,6 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
 		}
 		}
 		return ocispec.Manifest{}, err
 		return ocispec.Manifest{}, err
 	}
 	}
-
-	sort.SliceStable(m, func(i, j int) bool {
-		if m[i].p == nil {
-			return false
-		}
-		if m[j].p == nil {
-			return true
-		}
-		return platform.Less(*m[i].p, *m[j].p)
-	})
-
 	return *m[0].m, nil
 	return *m[0].m, nil
 }
 }
 
 
@@ -356,15 +357,11 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
 		}
 		}
 
 
 		descs = append(descs, index.Manifests...)
 		descs = append(descs, index.Manifests...)
-	case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip,
-		MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip,
-		MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig,
-		ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip,
-		ocispec.MediaTypeImageLayerNonDistributable, ocispec.MediaTypeImageLayerNonDistributableGzip,
-		MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig:
-		// childless data types.
-		return nil, nil
 	default:
 	default:
+		if IsLayerType(desc.MediaType) || IsKnownConfig(desc.MediaType) {
+			// childless data types.
+			return nil, nil
+		}
 		log.G(ctx).Warnf("encountered unknown type %v; children may not be fetched", desc.MediaType)
 		log.G(ctx).Warnf("encountered unknown type %v; children may not be fetched", desc.MediaType)
 	}
 	}
 
 
@@ -387,22 +384,3 @@ func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.D
 	}
 	}
 	return config.RootFS.DiffIDs, nil
 	return config.RootFS.DiffIDs, nil
 }
 }
-
-// IsCompressedDiff returns true if mediaType is a known compressed diff media type.
-// It returns false if the media type is a diff, but not compressed. If the media type
-// is not a known diff type, it returns errdefs.ErrNotImplemented
-func IsCompressedDiff(ctx context.Context, mediaType string) (bool, error) {
-	switch mediaType {
-	case ocispec.MediaTypeImageLayer, MediaTypeDockerSchema2Layer:
-	case ocispec.MediaTypeImageLayerGzip, MediaTypeDockerSchema2LayerGzip:
-		return true, nil
-	default:
-		// Still apply all generic media types *.tar[.+]gzip and *.tar
-		if strings.HasSuffix(mediaType, ".tar.gzip") || strings.HasSuffix(mediaType, ".tar+gzip") {
-			return true, nil
-		} else if !strings.HasSuffix(mediaType, ".tar") {
-			return false, errdefs.ErrNotImplemented
-		}
-	}
-	return false, nil
-}

+ 84 - 0
vendor/github.com/containerd/containerd/images/mediatypes.go

@@ -16,6 +16,15 @@
 
 
 package images
 package images
 
 
+import (
+	"context"
+	"sort"
+	"strings"
+
+	"github.com/containerd/containerd/errdefs"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
 // mediatype definitions for image components handled in containerd.
 // mediatype definitions for image components handled in containerd.
 //
 //
 // oci components are generally referenced directly, although we may centralize
 // oci components are generally referenced directly, although we may centralize
@@ -40,3 +49,78 @@ const (
 	// Legacy Docker schema1 manifest
 	// Legacy Docker schema1 manifest
 	MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
 	MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
 )
 )
+
+// DiffCompression returns the compression as defined by the layer diff media
+// type. For Docker media types without compression, "unknown" is returned to
+// indicate that the media type may be compressed. If the media type is not
+// recognized as a layer diff, then it returns errdefs.ErrNotImplemented
+func DiffCompression(ctx context.Context, mediaType string) (string, error) {
+	base, ext := parseMediaTypes(mediaType)
+	switch base {
+	case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerForeign:
+		if len(ext) > 0 {
+			// Type is wrapped
+			return "", nil
+		}
+		// These media types may have been compressed but failed to
+		// use the correct media type. The decompression function
+		// should detect and handle this case.
+		return "unknown", nil
+	case MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2LayerForeignGzip:
+		if len(ext) > 0 {
+			// Type is wrapped
+			return "", nil
+		}
+		return "gzip", nil
+	case ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerNonDistributable:
+		if len(ext) > 0 {
+			switch ext[len(ext)-1] {
+			case "gzip":
+				return "gzip", nil
+			}
+		}
+		return "", nil
+	default:
+		return "", errdefs.ErrNotImplemented
+	}
+}
+
+// parseMediaTypes splits the media type into the base type and
+// an array of sorted extensions
+func parseMediaTypes(mt string) (string, []string) {
+	if mt == "" {
+		return "", []string{}
+	}
+
+	s := strings.Split(mt, "+")
+	ext := s[1:]
+	sort.Strings(ext)
+
+	return s[0], ext
+}
+
+// IsLayerTypes returns true if the media type is a layer
+func IsLayerType(mt string) bool {
+	if strings.HasPrefix(mt, "application/vnd.oci.image.layer.") {
+		return true
+	}
+
+	// Parse Docker media types, strip off any + suffixes first
+	base, _ := parseMediaTypes(mt)
+	switch base {
+	case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip,
+		MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip:
+		return true
+	}
+	return false
+}
+
+// IsKnownConfig returns true if the media type is a known config type
+func IsKnownConfig(mt string) bool {
+	switch mt {
+	case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig,
+		MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig:
+		return true
+	}
+	return false
+}

+ 0 - 241
vendor/github.com/containerd/containerd/images/oci/exporter.go

@@ -1,241 +0,0 @@
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package oci
-
-import (
-	"archive/tar"
-	"context"
-	"encoding/json"
-	"io"
-	"sort"
-
-	"github.com/containerd/containerd/content"
-	"github.com/containerd/containerd/images"
-	"github.com/containerd/containerd/platforms"
-	ocispecs "github.com/opencontainers/image-spec/specs-go"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-	"github.com/pkg/errors"
-)
-
-// V1Exporter implements OCI Image Spec v1.
-// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
-//
-// TODO(AkihiroSuda): add V1Exporter{TranslateMediaTypes: true} that transforms media types,
-//                    e.g. application/vnd.docker.image.rootfs.diff.tar.gzip
-//                         -> application/vnd.oci.image.layer.v1.tar+gzip
-type V1Exporter struct {
-	AllPlatforms bool
-}
-
-// V1ExporterOpt allows the caller to set additional options to a new V1Exporter
-type V1ExporterOpt func(c *V1Exporter) error
-
-// DefaultV1Exporter return a default V1Exporter pointer
-func DefaultV1Exporter() *V1Exporter {
-	return &V1Exporter{
-		AllPlatforms: false,
-	}
-}
-
-// ResolveV1ExportOpt return a new V1Exporter with V1ExporterOpt
-func ResolveV1ExportOpt(opts ...V1ExporterOpt) (*V1Exporter, error) {
-	exporter := DefaultV1Exporter()
-	for _, o := range opts {
-		if err := o(exporter); err != nil {
-			return exporter, err
-		}
-	}
-	return exporter, nil
-}
-
-// WithAllPlatforms set V1Exporter`s AllPlatforms option
-func WithAllPlatforms(allPlatforms bool) V1ExporterOpt {
-	return func(c *V1Exporter) error {
-		c.AllPlatforms = allPlatforms
-		return nil
-	}
-}
-
-// Export implements Exporter.
-func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error {
-	tw := tar.NewWriter(writer)
-	defer tw.Close()
-
-	records := []tarRecord{
-		ociLayoutFile(""),
-		ociIndexRecord(desc),
-	}
-
-	algorithms := map[string]struct{}{}
-	exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
-		records = append(records, blobRecord(store, desc))
-		algorithms[desc.Digest.Algorithm().String()] = struct{}{}
-		return nil, nil
-	}
-
-	childrenHandler := images.ChildrenHandler(store)
-
-	if !oe.AllPlatforms {
-		// get local default platform to fetch image manifest
-		childrenHandler = images.FilterPlatforms(childrenHandler, platforms.Any(platforms.DefaultSpec()))
-	}
-
-	handlers := images.Handlers(
-		childrenHandler,
-		images.HandlerFunc(exportHandler),
-	)
-
-	// Walk sequentially since the number of fetchs is likely one and doing in
-	// parallel requires locking the export handler
-	if err := images.Walk(ctx, handlers, desc); err != nil {
-		return err
-	}
-
-	if len(algorithms) > 0 {
-		records = append(records, directoryRecord("blobs/", 0755))
-		for alg := range algorithms {
-			records = append(records, directoryRecord("blobs/"+alg+"/", 0755))
-		}
-	}
-
-	return writeTar(ctx, tw, records)
-}
-
-type tarRecord struct {
-	Header *tar.Header
-	CopyTo func(context.Context, io.Writer) (int64, error)
-}
-
-func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
-	path := "blobs/" + desc.Digest.Algorithm().String() + "/" + desc.Digest.Hex()
-	return tarRecord{
-		Header: &tar.Header{
-			Name:     path,
-			Mode:     0444,
-			Size:     desc.Size,
-			Typeflag: tar.TypeReg,
-		},
-		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
-			r, err := cs.ReaderAt(ctx, desc)
-			if err != nil {
-				return 0, errors.Wrap(err, "failed to get reader")
-			}
-			defer r.Close()
-
-			// Verify digest
-			dgstr := desc.Digest.Algorithm().Digester()
-
-			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
-			if err != nil {
-				return 0, errors.Wrap(err, "failed to copy to tar")
-			}
-			if dgstr.Digest() != desc.Digest {
-				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
-			}
-			return n, nil
-		},
-	}
-}
-
-func directoryRecord(name string, mode int64) tarRecord {
-	return tarRecord{
-		Header: &tar.Header{
-			Name:     name,
-			Mode:     mode,
-			Typeflag: tar.TypeDir,
-		},
-	}
-}
-
-func ociLayoutFile(version string) tarRecord {
-	if version == "" {
-		version = ocispec.ImageLayoutVersion
-	}
-	layout := ocispec.ImageLayout{
-		Version: version,
-	}
-
-	b, err := json.Marshal(layout)
-	if err != nil {
-		panic(err)
-	}
-
-	return tarRecord{
-		Header: &tar.Header{
-			Name:     ocispec.ImageLayoutFile,
-			Mode:     0444,
-			Size:     int64(len(b)),
-			Typeflag: tar.TypeReg,
-		},
-		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
-			n, err := w.Write(b)
-			return int64(n), err
-		},
-	}
-
-}
-
-func ociIndexRecord(manifests ...ocispec.Descriptor) tarRecord {
-	index := ocispec.Index{
-		Versioned: ocispecs.Versioned{
-			SchemaVersion: 2,
-		},
-		Manifests: manifests,
-	}
-
-	b, err := json.Marshal(index)
-	if err != nil {
-		panic(err)
-	}
-
-	return tarRecord{
-		Header: &tar.Header{
-			Name:     "index.json",
-			Mode:     0644,
-			Size:     int64(len(b)),
-			Typeflag: tar.TypeReg,
-		},
-		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
-			n, err := w.Write(b)
-			return int64(n), err
-		},
-	}
-}
-
-func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error {
-	sort.Slice(records, func(i, j int) bool {
-		return records[i].Header.Name < records[j].Header.Name
-	})
-
-	for _, record := range records {
-		if err := tw.WriteHeader(record.Header); err != nil {
-			return err
-		}
-		if record.CopyTo != nil {
-			n, err := record.CopyTo(ctx, tw)
-			if err != nil {
-				return err
-			}
-			if n != record.Header.Size {
-				return errors.Errorf("unexpected copy size for %s", record.Header.Name)
-			}
-		} else if record.Header.Size > 0 {
-			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
-		}
-	}
-	return nil
-}

+ 38 - 13
vendor/github.com/containerd/containerd/import.go

@@ -35,6 +35,7 @@ type importOpts struct {
 	imageRefT    func(string) string
 	imageRefT    func(string) string
 	dgstRefT     func(digest.Digest) string
 	dgstRefT     func(digest.Digest) string
 	allPlatforms bool
 	allPlatforms bool
+	compress     bool
 }
 }
 
 
 // ImportOpt allows the caller to specify import specific options
 // ImportOpt allows the caller to specify import specific options
@@ -74,9 +75,18 @@ func WithAllPlatforms(allPlatforms bool) ImportOpt {
 	}
 	}
 }
 }
 
 
+// WithImportCompression compresses uncompressed layers on import.
+// This is used for import formats which do not include the manifest.
+func WithImportCompression() ImportOpt {
+	return func(c *importOpts) error {
+		c.compress = true
+		return nil
+	}
+}
+
 // Import imports an image from a Tar stream using reader.
 // Import imports an image from a Tar stream using reader.
 // Caller needs to specify importer. Future version may use oci.v1 as the default.
 // Caller needs to specify importer. Future version may use oci.v1 as the default.
-// Note that unreferrenced blobs may be imported to the content store as well.
+// Note that unreferenced blobs may be imported to the content store as well.
 func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt) ([]images.Image, error) {
 func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt) ([]images.Image, error) {
 	var iopts importOpts
 	var iopts importOpts
 	for _, o := range opts {
 	for _, o := range opts {
@@ -91,7 +101,12 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
 	}
 	}
 	defer done(ctx)
 	defer done(ctx)
 
 
-	index, err := archive.ImportIndex(ctx, c.ContentStore(), reader)
+	var aio []archive.ImportOpt
+	if iopts.compress {
+		aio = append(aio, archive.WithImportCompression())
+	}
+
+	index, err := archive.ImportIndex(ctx, c.ContentStore(), reader, aio...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -110,7 +125,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
 	}
 	}
 	var platformMatcher = platforms.All
 	var platformMatcher = platforms.All
 	if !iopts.allPlatforms {
 	if !iopts.allPlatforms {
-		platformMatcher = platforms.Default()
+		platformMatcher = c.platform
 	}
 	}
 
 
 	var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
 	var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
@@ -130,16 +145,12 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
 		}
 		}
 
 
 		for _, m := range idx.Manifests {
 		for _, m := range idx.Manifests {
-			if ref := m.Annotations[ocispec.AnnotationRefName]; ref != "" {
-				if iopts.imageRefT != nil {
-					ref = iopts.imageRefT(ref)
-				}
-				if ref != "" {
-					imgs = append(imgs, images.Image{
-						Name:   ref,
-						Target: m,
-					})
-				}
+			name := imageName(m.Annotations, iopts.imageRefT)
+			if name != "" {
+				imgs = append(imgs, images.Image{
+					Name:   name,
+					Target: m,
+				})
 			}
 			}
 			if iopts.dgstRefT != nil {
 			if iopts.dgstRefT != nil {
 				ref := iopts.dgstRefT(m.Digest)
 				ref := iopts.dgstRefT(m.Digest)
@@ -178,3 +189,17 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
 
 
 	return imgs, nil
 	return imgs, nil
 }
 }
+
+func imageName(annotations map[string]string, ociCleanup func(string) string) string {
+	name := annotations[images.AnnotationImageName]
+	if name != "" {
+		return name
+	}
+	name = annotations[ocispec.AnnotationRefName]
+	if name != "" {
+		if ociCleanup != nil {
+			name = ociCleanup(name)
+		}
+	}
+	return name
+}

+ 1 - 2
vendor/github.com/containerd/containerd/install.go

@@ -27,7 +27,6 @@ import (
 	"github.com/containerd/containerd/archive/compression"
 	"github.com/containerd/containerd/archive/compression"
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/images"
-	"github.com/containerd/containerd/platforms"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
 
 
@@ -43,7 +42,7 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
 	}
 	}
 	var (
 	var (
 		cs       = image.ContentStore()
 		cs       = image.ContentStore()
-		platform = platforms.Default()
+		platform = c.platform
 	)
 	)
 	manifest, err := images.Manifest(ctx, cs, image.Target(), platform)
 	manifest, err := images.Manifest(ctx, cs, image.Target(), platform)
 	if err != nil {
 	if err != nil {

+ 10 - 0
vendor/github.com/containerd/containerd/leases/lease.go

@@ -32,6 +32,9 @@ type Manager interface {
 	Create(context.Context, ...Opt) (Lease, error)
 	Create(context.Context, ...Opt) (Lease, error)
 	Delete(context.Context, Lease, ...DeleteOpt) error
 	Delete(context.Context, Lease, ...DeleteOpt) error
 	List(context.Context, ...string) ([]Lease, error)
 	List(context.Context, ...string) ([]Lease, error)
+	AddResource(context.Context, Lease, Resource) error
+	DeleteResource(context.Context, Lease, Resource) error
+	ListResources(context.Context, Lease) ([]Resource, error)
 }
 }
 
 
 // Lease retains resources to prevent cleanup before
 // Lease retains resources to prevent cleanup before
@@ -42,6 +45,13 @@ type Lease struct {
 	Labels    map[string]string
 	Labels    map[string]string
 }
 }
 
 
+// Resource represents low level resource of image, like content, ingest and
+// snapshotter.
+type Resource struct {
+	ID   string
+	Type string
+}
+
 // DeleteOptions provide options on image delete
 // DeleteOptions provide options on image delete
 type DeleteOptions struct {
 type DeleteOptions struct {
 	Synchronous bool
 	Synchronous bool

+ 40 - 0
vendor/github.com/containerd/containerd/leases/proxy/manager.go

@@ -91,3 +91,43 @@ func (pm *proxyManager) List(ctx context.Context, filters ...string) ([]leases.L
 
 
 	return l, nil
 	return l, nil
 }
 }
+
+func (pm *proxyManager) AddResource(ctx context.Context, lease leases.Lease, r leases.Resource) error {
+	_, err := pm.client.AddResource(ctx, &leasesapi.AddResourceRequest{
+		ID: lease.ID,
+		Resource: leasesapi.Resource{
+			ID:   r.ID,
+			Type: r.Type,
+		},
+	})
+	return errdefs.FromGRPC(err)
+}
+
+func (pm *proxyManager) DeleteResource(ctx context.Context, lease leases.Lease, r leases.Resource) error {
+	_, err := pm.client.DeleteResource(ctx, &leasesapi.DeleteResourceRequest{
+		ID: lease.ID,
+		Resource: leasesapi.Resource{
+			ID:   r.ID,
+			Type: r.Type,
+		},
+	})
+	return errdefs.FromGRPC(err)
+}
+
+func (pm *proxyManager) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) {
+	resp, err := pm.client.ListResources(ctx, &leasesapi.ListResourcesRequest{
+		ID: lease.ID,
+	})
+	if err != nil {
+		return nil, errdefs.FromGRPC(err)
+	}
+
+	rs := make([]leases.Resource, 0, len(resp.Resources))
+	for _, i := range resp.Resources {
+		rs = append(rs, leases.Resource{
+			ID:   i.ID,
+			Type: i.Type,
+		})
+	}
+	return rs, nil
+}

+ 1 - 1
vendor/github.com/containerd/containerd/log/context.go

@@ -30,7 +30,7 @@ var (
 	// messages.
 	// messages.
 	G = GetLogger
 	G = GetLogger
 
 
-	// L is an alias for the the standard logger.
+	// L is an alias for the standard logger.
 	L = logrus.NewEntry(logrus.StandardLogger())
 	L = logrus.NewEntry(logrus.StandardLogger())
 )
 )
 
 

+ 145 - 114
vendor/github.com/containerd/containerd/metadata/containers.go

@@ -19,6 +19,7 @@ package metadata
 import (
 import (
 	"context"
 	"context"
 	"strings"
 	"strings"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/containers"
@@ -35,13 +36,13 @@ import (
 )
 )
 
 
 type containerStore struct {
 type containerStore struct {
-	tx *bolt.Tx
+	db *DB
 }
 }
 
 
 // NewContainerStore returns a Store backed by an underlying bolt DB
 // NewContainerStore returns a Store backed by an underlying bolt DB
-func NewContainerStore(tx *bolt.Tx) containers.Store {
+func NewContainerStore(db *DB) containers.Store {
 	return &containerStore{
 	return &containerStore{
-		tx: tx,
+		db: db,
 	}
 	}
 }
 }
 
 
@@ -51,14 +52,21 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
 		return containers.Container{}, err
 		return containers.Container{}, err
 	}
 	}
 
 
-	bkt := getContainerBucket(s.tx, namespace, id)
-	if bkt == nil {
-		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace)
-	}
-
 	container := containers.Container{ID: id}
 	container := containers.Container{ID: id}
-	if err := readContainer(&container, bkt); err != nil {
-		return containers.Container{}, errors.Wrapf(err, "failed to read container %q", id)
+
+	if err := view(ctx, s.db, func(tx *bolt.Tx) error {
+		bkt := getContainerBucket(tx, namespace, id)
+		if bkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace)
+		}
+
+		if err := readContainer(&container, bkt); err != nil {
+			return errors.Wrapf(err, "failed to read container %q", id)
+		}
+
+		return nil
+	}); err != nil {
+		return containers.Container{}, err
 	}
 	}
 
 
 	return container, nil
 	return container, nil
@@ -75,27 +83,30 @@ func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.C
 		return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
 		return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
 	}
 	}
 
 
-	bkt := getContainersBucket(s.tx, namespace)
-	if bkt == nil {
-		return nil, nil // empty store
-	}
-
 	var m []containers.Container
 	var m []containers.Container
-	if err := bkt.ForEach(func(k, v []byte) error {
-		cbkt := bkt.Bucket(k)
-		if cbkt == nil {
-			return nil
-		}
-		container := containers.Container{ID: string(k)}
 
 
-		if err := readContainer(&container, cbkt); err != nil {
-			return errors.Wrapf(err, "failed to read container %q", string(k))
+	if err := view(ctx, s.db, func(tx *bolt.Tx) error {
+		bkt := getContainersBucket(tx, namespace)
+		if bkt == nil {
+			return nil // empty store
 		}
 		}
 
 
-		if filter.Match(adaptContainer(container)) {
-			m = append(m, container)
-		}
-		return nil
+		return bkt.ForEach(func(k, v []byte) error {
+			cbkt := bkt.Bucket(k)
+			if cbkt == nil {
+				return nil
+			}
+			container := containers.Container{ID: string(k)}
+
+			if err := readContainer(&container, cbkt); err != nil {
+				return errors.Wrapf(err, "failed to read container %q", string(k))
+			}
+
+			if filter.Match(adaptContainer(container)) {
+				m = append(m, container)
+			}
+			return nil
+		})
 	}); err != nil {
 	}); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -113,23 +124,29 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
 		return containers.Container{}, errors.Wrap(err, "create container failed validation")
 		return containers.Container{}, errors.Wrap(err, "create container failed validation")
 	}
 	}
 
 
-	bkt, err := createContainersBucket(s.tx, namespace)
-	if err != nil {
-		return containers.Container{}, err
-	}
+	if err := update(ctx, s.db, func(tx *bolt.Tx) error {
+		bkt, err := createContainersBucket(tx, namespace)
+		if err != nil {
+			return err
+		}
 
 
-	cbkt, err := bkt.CreateBucket([]byte(container.ID))
-	if err != nil {
-		if err == bolt.ErrBucketExists {
-			err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID)
+		cbkt, err := bkt.CreateBucket([]byte(container.ID))
+		if err != nil {
+			if err == bolt.ErrBucketExists {
+				err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID)
+			}
+			return err
 		}
 		}
-		return containers.Container{}, err
-	}
 
 
-	container.CreatedAt = time.Now().UTC()
-	container.UpdatedAt = container.CreatedAt
-	if err := writeContainer(cbkt, &container); err != nil {
-		return containers.Container{}, errors.Wrapf(err, "failed to write container %q", container.ID)
+		container.CreatedAt = time.Now().UTC()
+		container.UpdatedAt = container.CreatedAt
+		if err := writeContainer(cbkt, &container); err != nil {
+			return errors.Wrapf(err, "failed to write container %q", container.ID)
+		}
+
+		return nil
+	}); err != nil {
+		return containers.Container{}, err
 	}
 	}
 
 
 	return container, nil
 	return container, nil
@@ -145,85 +162,91 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
 		return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
 		return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
 	}
 	}
 
 
-	bkt := getContainersBucket(s.tx, namespace)
-	if bkt == nil {
-		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace)
-	}
-
-	cbkt := bkt.Bucket([]byte(container.ID))
-	if cbkt == nil {
-		return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
-	}
-
 	var updated containers.Container
 	var updated containers.Container
-	if err := readContainer(&updated, cbkt); err != nil {
-		return updated, errors.Wrapf(err, "failed to read container %q", container.ID)
-	}
-	createdat := updated.CreatedAt
-	updated.ID = container.ID
-
-	if len(fieldpaths) == 0 {
-		// only allow updates to these field on full replace.
-		fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"}
-
-		// Fields that are immutable must cause an error when no field paths
-		// are provided. This allows these fields to become mutable in the
-		// future.
-		if updated.Snapshotter != container.Snapshotter {
-			return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
+	if err := update(ctx, s.db, func(tx *bolt.Tx) error {
+		bkt := getContainersBucket(tx, namespace)
+		if bkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace)
 		}
 		}
 
 
-		if updated.Runtime.Name != container.Runtime.Name {
-			return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable")
+		cbkt := bkt.Bucket([]byte(container.ID))
+		if cbkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
 		}
 		}
-	}
 
 
-	// apply the field mask. If you update this code, you better follow the
-	// field mask rules in field_mask.proto. If you don't know what this
-	// is, do not update this code.
-	for _, path := range fieldpaths {
-		if strings.HasPrefix(path, "labels.") {
-			if updated.Labels == nil {
-				updated.Labels = map[string]string{}
+		if err := readContainer(&updated, cbkt); err != nil {
+			return errors.Wrapf(err, "failed to read container %q", container.ID)
+		}
+		createdat := updated.CreatedAt
+		updated.ID = container.ID
+
+		if len(fieldpaths) == 0 {
+			// only allow updates to these field on full replace.
+			fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"}
+
+			// Fields that are immutable must cause an error when no field paths
+			// are provided. This allows these fields to become mutable in the
+			// future.
+			if updated.Snapshotter != container.Snapshotter {
+				return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
+			}
+
+			if updated.Runtime.Name != container.Runtime.Name {
+				return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable")
 			}
 			}
-			key := strings.TrimPrefix(path, "labels.")
-			updated.Labels[key] = container.Labels[key]
-			continue
 		}
 		}
 
 
-		if strings.HasPrefix(path, "extensions.") {
-			if updated.Extensions == nil {
-				updated.Extensions = map[string]types.Any{}
+		// apply the field mask. If you update this code, you better follow the
+		// field mask rules in field_mask.proto. If you don't know what this
+		// is, do not update this code.
+		for _, path := range fieldpaths {
+			if strings.HasPrefix(path, "labels.") {
+				if updated.Labels == nil {
+					updated.Labels = map[string]string{}
+				}
+				key := strings.TrimPrefix(path, "labels.")
+				updated.Labels[key] = container.Labels[key]
+				continue
+			}
+
+			if strings.HasPrefix(path, "extensions.") {
+				if updated.Extensions == nil {
+					updated.Extensions = map[string]types.Any{}
+				}
+				key := strings.TrimPrefix(path, "extensions.")
+				updated.Extensions[key] = container.Extensions[key]
+				continue
+			}
+
+			switch path {
+			case "labels":
+				updated.Labels = container.Labels
+			case "spec":
+				updated.Spec = container.Spec
+			case "extensions":
+				updated.Extensions = container.Extensions
+			case "image":
+				updated.Image = container.Image
+			case "snapshotkey":
+				updated.SnapshotKey = container.SnapshotKey
+			default:
+				return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
 			}
 			}
-			key := strings.TrimPrefix(path, "extensions.")
-			updated.Extensions[key] = container.Extensions[key]
-			continue
 		}
 		}
 
 
-		switch path {
-		case "labels":
-			updated.Labels = container.Labels
-		case "spec":
-			updated.Spec = container.Spec
-		case "extensions":
-			updated.Extensions = container.Extensions
-		case "image":
-			updated.Image = container.Image
-		case "snapshotkey":
-			updated.SnapshotKey = container.SnapshotKey
-		default:
-			return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
+		if err := validateContainer(&updated); err != nil {
+			return errors.Wrap(err, "update failed validation")
 		}
 		}
-	}
 
 
-	if err := validateContainer(&updated); err != nil {
-		return containers.Container{}, errors.Wrap(err, "update failed validation")
-	}
+		updated.CreatedAt = createdat
+		updated.UpdatedAt = time.Now().UTC()
+		if err := writeContainer(cbkt, &updated); err != nil {
+			return errors.Wrapf(err, "failed to write container %q", container.ID)
+		}
 
 
-	updated.CreatedAt = createdat
-	updated.UpdatedAt = time.Now().UTC()
-	if err := writeContainer(cbkt, &updated); err != nil {
-		return containers.Container{}, errors.Wrapf(err, "failed to write container %q", container.ID)
+		return nil
+	}); err != nil {
+		return containers.Container{}, err
 	}
 	}
 
 
 	return updated, nil
 	return updated, nil
@@ -235,15 +258,23 @@ func (s *containerStore) Delete(ctx context.Context, id string) error {
 		return err
 		return err
 	}
 	}
 
 
-	bkt := getContainersBucket(s.tx, namespace)
-	if bkt == nil {
-		return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace)
-	}
+	return update(ctx, s.db, func(tx *bolt.Tx) error {
+		bkt := getContainersBucket(tx, namespace)
+		if bkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace)
+		}
 
 
-	if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound {
-		return errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
-	}
-	return err
+		if err := bkt.DeleteBucket([]byte(id)); err != nil {
+			if err == bolt.ErrBucketNotFound {
+				err = errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
+			}
+			return err
+		}
+
+		atomic.AddUint32(&s.db.dirty, 1)
+
+		return nil
+	})
 }
 }
 
 
 func validateContainer(container *containers.Container) error {
 func validateContainer(container *containers.Container) error {

+ 5 - 3
vendor/github.com/containerd/containerd/metadata/content.go

@@ -21,6 +21,7 @@ import (
 	"encoding/binary"
 	"encoding/binary"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
@@ -221,9 +222,8 @@ func (cs *contentStore) Delete(ctx context.Context, dgst digest.Digest) error {
 		}
 		}
 
 
 		// Mark content store as dirty for triggering garbage collection
 		// Mark content store as dirty for triggering garbage collection
-		cs.db.dirtyL.Lock()
+		atomic.AddUint32(&cs.db.dirty, 1)
 		cs.db.dirtyCS = true
 		cs.db.dirtyCS = true
-		cs.db.dirtyL.Unlock()
 
 
 		return nil
 		return nil
 	})
 	})
@@ -567,6 +567,8 @@ func (nw *namespacedWriter) createAndCopy(ctx context.Context, desc ocispec.Desc
 }
 }
 
 
 func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
 func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
+	ctx = namespaces.WithNamespace(ctx, nw.namespace)
+
 	nw.l.RLock()
 	nw.l.RLock()
 	defer nw.l.RUnlock()
 	defer nw.l.RUnlock()
 
 
@@ -635,11 +637,11 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
 			return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "%q failed size validation: %v != %v", nw.ref, status.Offset, size)
 			return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "%q failed size validation: %v != %v", nw.ref, status.Offset, size)
 		}
 		}
 		size = status.Offset
 		size = status.Offset
-		actual = nw.w.Digest()
 
 
 		if err := nw.w.Commit(ctx, size, expected); err != nil && !errdefs.IsAlreadyExists(err) {
 		if err := nw.w.Commit(ctx, size, expected); err != nil && !errdefs.IsAlreadyExists(err) {
 			return "", err
 			return "", err
 		}
 		}
+		actual = nw.w.Digest()
 	}
 	}
 
 
 	bkt, err := createBlobBucket(tx, nw.namespace, actual)
 	bkt, err := createBlobBucket(tx, nw.namespace, actual)

+ 18 - 15
vendor/github.com/containerd/containerd/metadata/db.go

@@ -21,6 +21,7 @@ import (
 	"encoding/binary"
 	"encoding/binary"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/content"
@@ -75,10 +76,16 @@ type DB struct {
 	// sweep phases without preventing read transactions.
 	// sweep phases without preventing read transactions.
 	wlock sync.RWMutex
 	wlock sync.RWMutex
 
 
-	// dirty flags and lock keeps track of datastores which have had deletions
-	// since the last garbage collection. These datastores will will be garbage
-	// collected during the next garbage collection.
-	dirtyL  sync.Mutex
+	// dirty flag indicates that references have been removed which require
+	// a garbage collection to ensure the database is clean. This tracks
+	// the number of dirty operations. This should be updated and read
+	// atomically if outside of wlock.Lock.
+	dirty uint32
+
+	// dirtySS and dirtyCS flags keeps track of datastores which have had
+	// deletions since the last garbage collection. These datastores will
+	// be garbage collected during the next garbage collection. These
+	// should only be updated inside of a write transaction or wlock.Lock.
 	dirtySS map[string]struct{}
 	dirtySS map[string]struct{}
 	dirtyCS bool
 	dirtyCS bool
 
 
@@ -162,7 +169,7 @@ func (m *DB) Init(ctx context.Context) error {
 			}
 			}
 		}
 		}
 
 
-		// Previous version fo database found
+		// Previous version of database found
 		if schema != "v0" {
 		if schema != "v0" {
 			updates := migrations[i:]
 			updates := migrations[i:]
 
 
@@ -237,12 +244,10 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
 	defer m.wlock.RUnlock()
 	defer m.wlock.RUnlock()
 	err := m.db.Update(fn)
 	err := m.db.Update(fn)
 	if err == nil {
 	if err == nil {
-		m.dirtyL.Lock()
-		dirty := m.dirtyCS || len(m.dirtySS) > 0
+		dirty := atomic.LoadUint32(&m.dirty) > 0
 		for _, fn := range m.mutationCallbacks {
 		for _, fn := range m.mutationCallbacks {
 			fn(dirty)
 			fn(dirty)
 		}
 		}
-		m.dirtyL.Unlock()
 	}
 	}
 
 
 	return err
 	return err
@@ -254,9 +259,9 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
 // The callback function is an argument for whether a deletion has occurred
 // The callback function is an argument for whether a deletion has occurred
 // since the last garbage collection.
 // since the last garbage collection.
 func (m *DB) RegisterMutationCallback(fn func(bool)) {
 func (m *DB) RegisterMutationCallback(fn func(bool)) {
-	m.dirtyL.Lock()
+	m.wlock.Lock()
 	m.mutationCallbacks = append(m.mutationCallbacks, fn)
 	m.mutationCallbacks = append(m.mutationCallbacks, fn)
-	m.dirtyL.Unlock()
+	m.wlock.Unlock()
 }
 }
 
 
 // GCStats holds the duration for the different phases of the garbage collector
 // GCStats holds the duration for the different phases of the garbage collector
@@ -282,8 +287,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	m.dirtyL.Lock()
-
 	if err := m.db.Update(func(tx *bolt.Tx) error {
 	if err := m.db.Update(func(tx *bolt.Tx) error {
 		ctx, cancel := context.WithCancel(ctx)
 		ctx, cancel := context.WithCancel(ctx)
 		defer cancel()
 		defer cancel()
@@ -309,7 +312,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
 
 
 		return nil
 		return nil
 	}); err != nil {
 	}); err != nil {
-		m.dirtyL.Unlock()
 		m.wlock.Unlock()
 		m.wlock.Unlock()
 		return nil, err
 		return nil, err
 	}
 	}
@@ -317,6 +319,9 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
 	var stats GCStats
 	var stats GCStats
 	var wg sync.WaitGroup
 	var wg sync.WaitGroup
 
 
+	// reset dirty, no need for atomic inside of wlock.Lock
+	m.dirty = 0
+
 	if len(m.dirtySS) > 0 {
 	if len(m.dirtySS) > 0 {
 		var sl sync.Mutex
 		var sl sync.Mutex
 		stats.SnapshotD = map[string]time.Duration{}
 		stats.SnapshotD = map[string]time.Duration{}
@@ -349,8 +354,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
 		m.dirtyCS = false
 		m.dirtyCS = false
 	}
 	}
 
 
-	m.dirtyL.Unlock()
-
 	stats.MetaD = time.Since(t1)
 	stats.MetaD = time.Since(t1)
 	m.wlock.Unlock()
 	m.wlock.Unlock()
 
 

+ 33 - 6
vendor/github.com/containerd/containerd/metadata/gc.go

@@ -46,11 +46,17 @@ const (
 	ResourceIngest
 	ResourceIngest
 )
 )
 
 
+const (
+	resourceContentFlat  = ResourceContent | 0x20
+	resourceSnapshotFlat = ResourceSnapshot | 0x20
+)
+
 var (
 var (
 	labelGCRoot       = []byte("containerd.io/gc.root")
 	labelGCRoot       = []byte("containerd.io/gc.root")
 	labelGCSnapRef    = []byte("containerd.io/gc.ref.snapshot.")
 	labelGCSnapRef    = []byte("containerd.io/gc.ref.snapshot.")
 	labelGCContentRef = []byte("containerd.io/gc.ref.content")
 	labelGCContentRef = []byte("containerd.io/gc.ref.content")
 	labelGCExpire     = []byte("containerd.io/gc.expire")
 	labelGCExpire     = []byte("containerd.io/gc.expire")
+	labelGCFlat       = []byte("containerd.io/gc.flat")
 )
 )
 
 
 func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
 func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
@@ -90,6 +96,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
 					return nil
 					return nil
 				}
 				}
 				libkt := lbkt.Bucket(k)
 				libkt := lbkt.Bucket(k)
+				var flat bool
 
 
 				if lblbkt := libkt.Bucket(bucketKeyObjectLabels); lblbkt != nil {
 				if lblbkt := libkt.Bucket(bucketKeyObjectLabels); lblbkt != nil {
 					if expV := lblbkt.Get(labelGCExpire); expV != nil {
 					if expV := lblbkt.Get(labelGCExpire); expV != nil {
@@ -102,6 +109,10 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
 							return nil
 							return nil
 						}
 						}
 					}
 					}
+
+					if flatV := lblbkt.Get(labelGCFlat); flatV != nil {
+						flat = true
+					}
 				}
 				}
 
 
 				fn(gcnode(ResourceLease, ns, string(k)))
 				fn(gcnode(ResourceLease, ns, string(k)))
@@ -111,16 +122,26 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
 				// no need to allow the lookup to be recursive, handling here
 				// no need to allow the lookup to be recursive, handling here
 				// therefore reduces the number of database seeks.
 				// therefore reduces the number of database seeks.
 
 
+				ctype := ResourceContent
+				if flat {
+					ctype = resourceContentFlat
+				}
+
 				cbkt := libkt.Bucket(bucketKeyObjectContent)
 				cbkt := libkt.Bucket(bucketKeyObjectContent)
 				if cbkt != nil {
 				if cbkt != nil {
 					if err := cbkt.ForEach(func(k, v []byte) error {
 					if err := cbkt.ForEach(func(k, v []byte) error {
-						fn(gcnode(ResourceContent, ns, string(k)))
+						fn(gcnode(ctype, ns, string(k)))
 						return nil
 						return nil
 					}); err != nil {
 					}); err != nil {
 						return err
 						return err
 					}
 					}
 				}
 				}
 
 
+				stype := ResourceSnapshot
+				if flat {
+					stype = resourceSnapshotFlat
+				}
+
 				sbkt := libkt.Bucket(bucketKeyObjectSnapshots)
 				sbkt := libkt.Bucket(bucketKeyObjectSnapshots)
 				if sbkt != nil {
 				if sbkt != nil {
 					if err := sbkt.ForEach(func(sk, sv []byte) error {
 					if err := sbkt.ForEach(func(sk, sv []byte) error {
@@ -130,7 +151,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
 						snbkt := sbkt.Bucket(sk)
 						snbkt := sbkt.Bucket(sk)
 
 
 						return snbkt.ForEach(func(k, v []byte) error {
 						return snbkt.ForEach(func(k, v []byte) error {
-							fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)))
+							fn(gcnode(stype, ns, fmt.Sprintf("%s/%s", sk, k)))
 							return nil
 							return nil
 						})
 						})
 					}); err != nil {
 					}); err != nil {
@@ -257,7 +278,8 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
 }
 }
 
 
 func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)) error {
 func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)) error {
-	if node.Type == ResourceContent {
+	switch node.Type {
+	case ResourceContent:
 		bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(node.Key))
 		bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(node.Key))
 		if bkt == nil {
 		if bkt == nil {
 			// Node may be created from dead edge
 			// Node may be created from dead edge
@@ -265,7 +287,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
 		}
 		}
 
 
 		return sendLabelRefs(node.Namespace, bkt, fn)
 		return sendLabelRefs(node.Namespace, bkt, fn)
-	} else if node.Type == ResourceSnapshot {
+	case ResourceSnapshot, resourceSnapshotFlat:
 		parts := strings.SplitN(node.Key, "/", 2)
 		parts := strings.SplitN(node.Key, "/", 2)
 		if len(parts) != 2 {
 		if len(parts) != 2 {
 			return errors.Errorf("invalid snapshot gc key %s", node.Key)
 			return errors.Errorf("invalid snapshot gc key %s", node.Key)
@@ -280,11 +302,16 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
 		}
 		}
 
 
 		if pv := bkt.Get(bucketKeyParent); len(pv) > 0 {
 		if pv := bkt.Get(bucketKeyParent); len(pv) > 0 {
-			fn(gcnode(ResourceSnapshot, node.Namespace, fmt.Sprintf("%s/%s", ss, pv)))
+			fn(gcnode(node.Type, node.Namespace, fmt.Sprintf("%s/%s", ss, pv)))
+		}
+
+		// Do not send labeled references for flat snapshot refs
+		if node.Type == resourceSnapshotFlat {
+			return nil
 		}
 		}
 
 
 		return sendLabelRefs(node.Namespace, bkt, fn)
 		return sendLabelRefs(node.Namespace, bkt, fn)
-	} else if node.Type == ResourceIngest {
+	case ResourceIngest:
 		// Send expected value
 		// Send expected value
 		bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(node.Key))
 		bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(node.Key))
 		if bkt == nil {
 		if bkt == nil {

+ 8 - 10
vendor/github.com/containerd/containerd/metadata/images.go

@@ -21,6 +21,7 @@ import (
 	"encoding/binary"
 	"encoding/binary"
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
@@ -249,19 +250,16 @@ func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.Del
 			return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
 			return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
 		}
 		}
 
 
-		err = bkt.DeleteBucket([]byte(name))
-		if err == bolt.ErrBucketNotFound {
-			return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
+		if err = bkt.DeleteBucket([]byte(name)); err != nil {
+			if err == bolt.ErrBucketNotFound {
+				err = errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
+			}
+			return err
 		}
 		}
 
 
-		// A reference to a piece of content has been removed,
-		// mark content store as dirty for triggering garbage
-		// collection
-		s.db.dirtyL.Lock()
-		s.db.dirtyCS = true
-		s.db.dirtyL.Unlock()
+		atomic.AddUint32(&s.db.dirty, 1)
 
 
-		return err
+		return nil
 	})
 	})
 }
 }
 
 

+ 242 - 56
vendor/github.com/containerd/containerd/metadata/leases.go

@@ -18,6 +18,9 @@ package metadata
 
 
 import (
 import (
 	"context"
 	"context"
+	"fmt"
+	"strings"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
@@ -30,17 +33,17 @@ import (
 	bolt "go.etcd.io/bbolt"
 	bolt "go.etcd.io/bbolt"
 )
 )
 
 
-// LeaseManager manages the create/delete lifecyle of leases
+// LeaseManager manages the create/delete lifecycle of leases
 // and also returns existing leases
 // and also returns existing leases
 type LeaseManager struct {
 type LeaseManager struct {
-	tx *bolt.Tx
+	db *DB
 }
 }
 
 
 // NewLeaseManager creates a new lease manager for managing leases using
 // NewLeaseManager creates a new lease manager for managing leases using
 // the provided database transaction.
 // the provided database transaction.
-func NewLeaseManager(tx *bolt.Tx) *LeaseManager {
+func NewLeaseManager(db *DB) *LeaseManager {
 	return &LeaseManager{
 	return &LeaseManager{
-		tx: tx,
+		db: db,
 	}
 	}
 }
 }
 
 
@@ -61,56 +64,66 @@ func (lm *LeaseManager) Create(ctx context.Context, opts ...leases.Opt) (leases.
 		return leases.Lease{}, err
 		return leases.Lease{}, err
 	}
 	}
 
 
-	topbkt, err := createBucketIfNotExists(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
-	if err != nil {
-		return leases.Lease{}, err
-	}
+	if err := update(ctx, lm.db, func(tx *bolt.Tx) error {
+		topbkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
+		if err != nil {
+			return err
+		}
 
 
-	txbkt, err := topbkt.CreateBucket([]byte(l.ID))
-	if err != nil {
-		if err == bolt.ErrBucketExists {
-			err = errdefs.ErrAlreadyExists
+		txbkt, err := topbkt.CreateBucket([]byte(l.ID))
+		if err != nil {
+			if err == bolt.ErrBucketExists {
+				err = errdefs.ErrAlreadyExists
+			}
+			return errors.Wrapf(err, "lease %q", l.ID)
 		}
 		}
-		return leases.Lease{}, errors.Wrapf(err, "lease %q", l.ID)
-	}
 
 
-	t := time.Now().UTC()
-	createdAt, err := t.MarshalBinary()
-	if err != nil {
-		return leases.Lease{}, err
-	}
-	if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
-		return leases.Lease{}, err
-	}
+		t := time.Now().UTC()
+		createdAt, err := t.MarshalBinary()
+		if err != nil {
+			return err
+		}
+		if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
+			return err
+		}
 
 
-	if l.Labels != nil {
-		if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil {
-			return leases.Lease{}, err
+		if l.Labels != nil {
+			if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil {
+				return err
+			}
 		}
 		}
-	}
-	l.CreatedAt = t
+		l.CreatedAt = t
 
 
+		return nil
+	}); err != nil {
+		return leases.Lease{}, err
+	}
 	return l, nil
 	return l, nil
 }
 }
 
 
-// Delete delets the lease with the provided lease ID
+// Delete deletes the lease with the provided lease ID
 func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease, _ ...leases.DeleteOpt) error {
 func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease, _ ...leases.DeleteOpt) error {
 	namespace, err := namespaces.NamespaceRequired(ctx)
 	namespace, err := namespaces.NamespaceRequired(ctx)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
-	if topbkt == nil {
-		return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
-	}
-	if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil {
-		if err == bolt.ErrBucketNotFound {
-			err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
+	return update(ctx, lm.db, func(tx *bolt.Tx) error {
+		topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
+		if topbkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
 		}
 		}
-		return err
-	}
-	return nil
+		if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil {
+			if err == bolt.ErrBucketNotFound {
+				err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
+			}
+			return err
+		}
+
+		atomic.AddUint32(&lm.db.dirty, 1)
+
+		return nil
+	})
 }
 }
 
 
 // List lists all active leases
 // List lists all active leases
@@ -127,44 +140,184 @@ func (lm *LeaseManager) List(ctx context.Context, fs ...string) ([]leases.Lease,
 
 
 	var ll []leases.Lease
 	var ll []leases.Lease
 
 
-	topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
-	if topbkt == nil {
-		return ll, nil
-	}
+	if err := view(ctx, lm.db, func(tx *bolt.Tx) error {
+		topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
+		if topbkt == nil {
+			return nil
+		}
+
+		return topbkt.ForEach(func(k, v []byte) error {
+			if v != nil {
+				return nil
+			}
+			txbkt := topbkt.Bucket(k)
+
+			l := leases.Lease{
+				ID: string(k),
+			}
+
+			if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
+				t := &l.CreatedAt
+				if err := t.UnmarshalBinary(v); err != nil {
+					return err
+				}
+			}
+
+			labels, err := boltutil.ReadLabels(txbkt)
+			if err != nil {
+				return err
+			}
+			l.Labels = labels
+
+			if filter.Match(adaptLease(l)) {
+				ll = append(ll, l)
+			}
 
 
-	if err := topbkt.ForEach(func(k, v []byte) error {
-		if v != nil {
 			return nil
 			return nil
+		})
+	}); err != nil {
+		return nil, err
+	}
+
+	return ll, nil
+}
+
+// AddResource references the resource by the provided lease.
+func (lm *LeaseManager) AddResource(ctx context.Context, lease leases.Lease, r leases.Resource) error {
+	namespace, err := namespaces.NamespaceRequired(ctx)
+	if err != nil {
+		return err
+	}
+
+	return update(ctx, lm.db, func(tx *bolt.Tx) error {
+		topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
+		if topbkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
 		}
 		}
-		txbkt := topbkt.Bucket(k)
 
 
-		l := leases.Lease{
-			ID: string(k),
+		keys, ref, err := parseLeaseResource(r)
+		if err != nil {
+			return err
 		}
 		}
 
 
-		if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
-			t := &l.CreatedAt
-			if err := t.UnmarshalBinary(v); err != nil {
+		bkt := topbkt
+		for _, key := range keys {
+			bkt, err = bkt.CreateBucketIfNotExists([]byte(key))
+			if err != nil {
 				return err
 				return err
 			}
 			}
 		}
 		}
+		return bkt.Put([]byte(ref), nil)
+	})
+}
 
 
-		labels, err := boltutil.ReadLabels(txbkt)
+// DeleteResource dereferences the resource by the provided lease.
+func (lm *LeaseManager) DeleteResource(ctx context.Context, lease leases.Lease, r leases.Resource) error {
+	namespace, err := namespaces.NamespaceRequired(ctx)
+	if err != nil {
+		return err
+	}
+
+	return update(ctx, lm.db, func(tx *bolt.Tx) error {
+		topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
+		if topbkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
+		}
+
+		keys, ref, err := parseLeaseResource(r)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		l.Labels = labels
 
 
-		if filter.Match(adaptLease(l)) {
-			ll = append(ll, l)
+		bkt := topbkt
+		for _, key := range keys {
+			if bkt == nil {
+				break
+			}
+			bkt = bkt.Bucket([]byte(key))
+		}
+
+		if bkt != nil {
+			if err := bkt.Delete([]byte(ref)); err != nil {
+				return err
+			}
 		}
 		}
 
 
+		atomic.AddUint32(&lm.db.dirty, 1)
+
 		return nil
 		return nil
-	}); err != nil {
+	})
+}
+
+// ListResources lists all the resources referenced by the lease.
+func (lm *LeaseManager) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) {
+	namespace, err := namespaces.NamespaceRequired(ctx)
+	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return ll, nil
+	var rs []leases.Resource
+
+	if err := view(ctx, lm.db, func(tx *bolt.Tx) error {
+
+		topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
+		if topbkt == nil {
+			return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
+		}
+
+		// content resources
+		if cbkt := topbkt.Bucket(bucketKeyObjectContent); cbkt != nil {
+			if err := cbkt.ForEach(func(k, _ []byte) error {
+				rs = append(rs, leases.Resource{
+					ID:   string(k),
+					Type: string(bucketKeyObjectContent),
+				})
+
+				return nil
+			}); err != nil {
+				return err
+			}
+		}
+
+		// ingest resources
+		if lbkt := topbkt.Bucket(bucketKeyObjectIngests); lbkt != nil {
+			if err := lbkt.ForEach(func(k, _ []byte) error {
+				rs = append(rs, leases.Resource{
+					ID:   string(k),
+					Type: string(bucketKeyObjectIngests),
+				})
+
+				return nil
+			}); err != nil {
+				return err
+			}
+		}
+
+		// snapshot resources
+		if sbkt := topbkt.Bucket(bucketKeyObjectSnapshots); sbkt != nil {
+			if err := sbkt.ForEach(func(sk, sv []byte) error {
+				if sv != nil {
+					return nil
+				}
+
+				snbkt := sbkt.Bucket(sk)
+				return snbkt.ForEach(func(k, _ []byte) error {
+					rs = append(rs, leases.Resource{
+						ID:   string(k),
+						Type: fmt.Sprintf("%s/%s", bucketKeyObjectSnapshots, sk),
+					})
+					return nil
+				})
+			}); err != nil {
+				return err
+			}
+		}
+
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+	return rs, nil
 }
 }
 
 
 func addSnapshotLease(ctx context.Context, tx *bolt.Tx, snapshotter, key string) error {
 func addSnapshotLease(ctx context.Context, tx *bolt.Tx, snapshotter, key string) error {
@@ -307,3 +460,36 @@ func removeIngestLease(ctx context.Context, tx *bolt.Tx, ref string) error {
 
 
 	return bkt.Delete([]byte(ref))
 	return bkt.Delete([]byte(ref))
 }
 }
+
+func parseLeaseResource(r leases.Resource) ([]string, string, error) {
+	var (
+		ref  = r.ID
+		typ  = r.Type
+		keys = strings.Split(typ, "/")
+	)
+
+	switch k := keys[0]; k {
+	case string(bucketKeyObjectContent),
+		string(bucketKeyObjectIngests):
+
+		if len(keys) != 1 {
+			return nil, "", errors.Wrapf(errdefs.ErrInvalidArgument, "invalid resource type %s", typ)
+		}
+
+		if k == string(bucketKeyObjectContent) {
+			dgst, err := digest.Parse(ref)
+			if err != nil {
+				return nil, "", errors.Wrapf(errdefs.ErrInvalidArgument, "invalid content resource id %s: %v", ref, err)
+			}
+			ref = dgst.String()
+		}
+	case string(bucketKeyObjectSnapshots):
+		if len(keys) != 2 {
+			return nil, "", errors.Wrapf(errdefs.ErrInvalidArgument, "invalid snapshot resource type %s", typ)
+		}
+	default:
+		return nil, "", errors.Wrapf(errdefs.ErrNotImplemented, "resource type %s not supported yet", typ)
+	}
+
+	return keys, ref, nil
+}

+ 9 - 1
vendor/github.com/containerd/containerd/metadata/namespaces.go

@@ -129,7 +129,15 @@ func (s *namespaceStore) List(ctx context.Context) ([]string, error) {
 	return namespaces, nil
 	return namespaces, nil
 }
 }
 
 
-func (s *namespaceStore) Delete(ctx context.Context, namespace string) error {
+func (s *namespaceStore) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error {
+	i := &namespaces.DeleteInfo{
+		Name: namespace,
+	}
+	for _, o := range opts {
+		if err := o(ctx, i); err != nil {
+			return err
+		}
+	}
 	bkt := getBucket(s.tx, bucketKeyVersion)
 	bkt := getBucket(s.tx, bucketKeyVersion)
 	if empty, err := s.namespaceEmpty(ctx, namespace); err != nil {
 	if empty, err := s.namespaceEmpty(ctx, namespace); err != nil {
 		return err
 		return err

+ 38 - 5
vendor/github.com/containerd/containerd/metadata/snapshot.go

@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
@@ -34,6 +35,10 @@ import (
 	bolt "go.etcd.io/bbolt"
 	bolt "go.etcd.io/bbolt"
 )
 )
 
 
+const (
+	inheritedLabelsPrefix = "containerd.io/snapshot/"
+)
+
 type snapshotter struct {
 type snapshotter struct {
 	snapshots.Snapshotter
 	snapshots.Snapshotter
 	name string
 	name string
@@ -209,6 +214,15 @@ func (s *snapshotter) Update(ctx context.Context, info snapshots.Info, fieldpath
 		bkey = string(sbkt.Get(bucketKeyName))
 		bkey = string(sbkt.Get(bucketKeyName))
 		local.Parent = string(sbkt.Get(bucketKeyParent))
 		local.Parent = string(sbkt.Get(bucketKeyParent))
 
 
+		inner := snapshots.Info{
+			Name:   bkey,
+			Labels: filterInheritedLabels(local.Labels),
+		}
+
+		if _, err := s.Snapshotter.Update(ctx, inner, fieldpaths...); err != nil {
+			return err
+		}
+
 		return nil
 		return nil
 	}); err != nil {
 	}); err != nil {
 		return snapshots.Info{}, err
 		return snapshots.Info{}, err
@@ -338,12 +352,14 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re
 			return err
 			return err
 		}
 		}
 
 
+		inheritedOpt := snapshots.WithLabels(filterInheritedLabels(base.Labels))
+
 		// TODO: Consider doing this outside of transaction to lessen
 		// TODO: Consider doing this outside of transaction to lessen
 		// metadata lock time
 		// metadata lock time
 		if readonly {
 		if readonly {
-			m, err = s.Snapshotter.View(ctx, bkey, bparent)
+			m, err = s.Snapshotter.View(ctx, bkey, bparent, inheritedOpt)
 		} else {
 		} else {
-			m, err = s.Snapshotter.Prepare(ctx, bkey, bparent)
+			m, err = s.Snapshotter.Prepare(ctx, bkey, bparent, inheritedOpt)
 		}
 		}
 		return err
 		return err
 	}); err != nil {
 	}); err != nil {
@@ -445,9 +461,11 @@ func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snap
 			return err
 			return err
 		}
 		}
 
 
+		inheritedOpt := snapshots.WithLabels(filterInheritedLabels(base.Labels))
+
 		// TODO: Consider doing this outside of transaction to lessen
 		// TODO: Consider doing this outside of transaction to lessen
 		// metadata lock time
 		// metadata lock time
-		return s.Snapshotter.Commit(ctx, nameKey, bkey)
+		return s.Snapshotter.Commit(ctx, nameKey, bkey, inheritedOpt)
 	})
 	})
 
 
 }
 }
@@ -500,9 +518,8 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error {
 		}
 		}
 
 
 		// Mark snapshotter as dirty for triggering garbage collection
 		// Mark snapshotter as dirty for triggering garbage collection
-		s.db.dirtyL.Lock()
+		atomic.AddUint32(&s.db.dirty, 1)
 		s.db.dirtySS[s.name] = struct{}{}
 		s.db.dirtySS[s.name] = struct{}{}
-		s.db.dirtyL.Unlock()
 
 
 		return nil
 		return nil
 	})
 	})
@@ -761,3 +778,19 @@ func (s *snapshotter) pruneBranch(ctx context.Context, node *treeNode) error {
 func (s *snapshotter) Close() error {
 func (s *snapshotter) Close() error {
 	return s.Snapshotter.Close()
 	return s.Snapshotter.Close()
 }
 }
+
+// filterInheritedLabels filters the provided labels by removing any key which doesn't have
+// a prefix of "containerd.io/snapshot/".
+func filterInheritedLabels(labels map[string]string) map[string]string {
+	if labels == nil {
+		return nil
+	}
+
+	filtered := make(map[string]string)
+	for k, v := range labels {
+		if strings.HasPrefix(k, inheritedLabelsPrefix) {
+			filtered[k] = v
+		}
+	}
+	return filtered
+}

+ 12 - 4
vendor/github.com/containerd/containerd/namespaces.go

@@ -100,10 +100,18 @@ func (r *remoteNamespaces) List(ctx context.Context) ([]string, error) {
 	return namespaces, nil
 	return namespaces, nil
 }
 }
 
 
-func (r *remoteNamespaces) Delete(ctx context.Context, namespace string) error {
-	var req api.DeleteNamespaceRequest
-
-	req.Name = namespace
+func (r *remoteNamespaces) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error {
+	i := namespaces.DeleteInfo{
+		Name: namespace,
+	}
+	for _, o := range opts {
+		if err := o(ctx, &i); err != nil {
+			return err
+		}
+	}
+	req := api.DeleteNamespaceRequest{
+		Name: namespace,
+	}
 	_, err := r.client.Delete(ctx, &req)
 	_, err := r.client.Delete(ctx, &req)
 	if err != nil {
 	if err != nil {
 		return errdefs.FromGRPC(err)
 		return errdefs.FromGRPC(err)

+ 6 - 8
vendor/github.com/containerd/containerd/namespaces/context.go

@@ -36,10 +36,9 @@ type namespaceKey struct{}
 // WithNamespace sets a given namespace on the context
 // WithNamespace sets a given namespace on the context
 func WithNamespace(ctx context.Context, namespace string) context.Context {
 func WithNamespace(ctx context.Context, namespace string) context.Context {
 	ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace
 	ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace
-
-	// also store on the grpc headers so it gets picked up by any clients that
+	// also store on the grpc and ttrpc headers so it gets picked up by any clients that
 	// are using this.
 	// are using this.
-	return withGRPCNamespaceHeader(ctx, namespace)
+	return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace)
 }
 }
 
 
 // NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or
 // NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or
@@ -58,22 +57,21 @@ func NamespaceFromEnv(ctx context.Context) context.Context {
 func Namespace(ctx context.Context) (string, bool) {
 func Namespace(ctx context.Context) (string, bool) {
 	namespace, ok := ctx.Value(namespaceKey{}).(string)
 	namespace, ok := ctx.Value(namespaceKey{}).(string)
 	if !ok {
 	if !ok {
-		return fromGRPCHeader(ctx)
+		if namespace, ok = fromGRPCHeader(ctx); !ok {
+			return fromTTRPCHeader(ctx)
+		}
 	}
 	}
-
 	return namespace, ok
 	return namespace, ok
 }
 }
 
 
-// NamespaceRequired returns the valid namepace from the context or an error.
+// NamespaceRequired returns the valid namespace from the context or an error.
 func NamespaceRequired(ctx context.Context) (string, error) {
 func NamespaceRequired(ctx context.Context) (string, error) {
 	namespace, ok := Namespace(ctx)
 	namespace, ok := Namespace(ctx)
 	if !ok || namespace == "" {
 	if !ok || namespace == "" {
 		return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required")
 		return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required")
 	}
 	}
-
 	if err := Validate(namespace); err != nil {
 	if err := Validate(namespace); err != nil {
 		return "", errors.Wrap(err, "namespace validation")
 		return "", errors.Wrap(err, "namespace validation")
 	}
 	}
-
 	return namespace, nil
 	return namespace, nil
 }
 }

+ 10 - 1
vendor/github.com/containerd/containerd/namespaces/store.go

@@ -33,5 +33,14 @@ type Store interface {
 	List(ctx context.Context) ([]string, error)
 	List(ctx context.Context) ([]string, error)
 
 
 	// Delete removes the namespace. The namespace must be empty to be deleted.
 	// Delete removes the namespace. The namespace must be empty to be deleted.
-	Delete(ctx context.Context, namespace string) error
+	Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error
 }
 }
+
+// DeleteInfo specifies information for the deletion of a namespace
+type DeleteInfo struct {
+	// Name of the namespace
+	Name string
+}
+
+// DeleteOpts allows the caller to set options for namespace deletion
+type DeleteOpts func(context.Context, *DeleteInfo) error

+ 51 - 0
vendor/github.com/containerd/containerd/namespaces/ttrpc.go

@@ -0,0 +1,51 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package namespaces
+
+import (
+	"context"
+
+	"github.com/containerd/ttrpc"
+)
+
+const (
+	// TTRPCHeader defines the header name for specifying a containerd namespace
+	TTRPCHeader = "containerd-namespace-ttrpc"
+)
+
+func copyMetadata(src ttrpc.MD) ttrpc.MD {
+	md := ttrpc.MD{}
+	for k, v := range src {
+		md[k] = append(md[k], v...)
+	}
+	return md
+}
+
+func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
+	md, ok := ttrpc.GetMetadata(ctx)
+	if !ok {
+		md = ttrpc.MD{}
+	} else {
+		md = copyMetadata(md)
+	}
+	md.Set(TTRPCHeader, namespace)
+	return ttrpc.WithMetadata(ctx, md)
+}
+
+func fromTTRPCHeader(ctx context.Context) (string, bool) {
+	return ttrpc.GetMetadataValue(ctx, TTRPCHeader)
+}

+ 1 - 2
vendor/github.com/containerd/containerd/oci/spec.go

@@ -78,7 +78,7 @@ func generateDefaultSpecWithPlatform(ctx context.Context, platform, id string, s
 	return err
 	return err
 }
 }
 
 
-// ApplyOpts applys the options to the given spec, injecting data from the
+// ApplyOpts applies the options to the given spec, injecting data from the
 // context, client and container instance.
 // context, client and container instance.
 func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
 func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
 	for _, o := range opts {
 	for _, o := range opts {
@@ -141,7 +141,6 @@ func populateDefaultUnixSpec(ctx context.Context, s *Spec, id string) error {
 			Path: defaultRootfsPath,
 			Path: defaultRootfsPath,
 		},
 		},
 		Process: &specs.Process{
 		Process: &specs.Process{
-			Env:             defaultUnixEnv,
 			Cwd:             "/",
 			Cwd:             "/",
 			NoNewPrivileges: true,
 			NoNewPrivileges: true,
 			User: specs.User{
 			User: specs.User{

+ 112 - 4
vendor/github.com/containerd/containerd/oci/spec_opts.go

@@ -17,6 +17,7 @@
 package oci
 package oci
 
 
 import (
 import (
+	"bufio"
 	"context"
 	"context"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
@@ -76,6 +77,20 @@ func setLinux(s *Spec) {
 	}
 	}
 }
 }
 
 
+// nolint
+func setResources(s *Spec) {
+	if s.Linux != nil {
+		if s.Linux.Resources == nil {
+			s.Linux.Resources = &specs.LinuxResources{}
+		}
+	}
+	if s.Windows != nil {
+		if s.Windows.Resources == nil {
+			s.Windows.Resources = &specs.WindowsResources{}
+		}
+	}
+}
+
 // setCapabilities sets Linux Capabilities to empty if unset
 // setCapabilities sets Linux Capabilities to empty if unset
 func setCapabilities(s *Spec) {
 func setCapabilities(s *Spec) {
 	setProcess(s)
 	setProcess(s)
@@ -104,7 +119,7 @@ func WithDefaultSpecForPlatform(platform string) SpecOpts {
 	}
 	}
 }
 }
 
 
-// WithSpecFromBytes loads the the spec from the provided byte slice.
+// WithSpecFromBytes loads the spec from the provided byte slice.
 func WithSpecFromBytes(p []byte) SpecOpts {
 func WithSpecFromBytes(p []byte) SpecOpts {
 	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
 	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
 		*s = Spec{} // make sure spec is cleared.
 		*s = Spec{} // make sure spec is cleared.
@@ -137,6 +152,13 @@ func WithEnv(environmentVariables []string) SpecOpts {
 	}
 	}
 }
 }
 
 
+// WithDefaultPathEnv sets the $PATH environment variable to the
+// default PATH defined in this package.
+func WithDefaultPathEnv(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
+	s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, defaultUnixEnv)
+	return nil
+}
+
 // replaceOrAppendEnvValues returns the defaults with the overrides either
 // replaceOrAppendEnvValues returns the defaults with the overrides either
 // replaced by env key or appended to the list
 // replaced by env key or appended to the list
 func replaceOrAppendEnvValues(defaults, overrides []string) []string {
 func replaceOrAppendEnvValues(defaults, overrides []string) []string {
@@ -312,7 +334,11 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
 
 
 		setProcess(s)
 		setProcess(s)
 		if s.Linux != nil {
 		if s.Linux != nil {
-			s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env)
+			defaults := config.Env
+			if len(defaults) == 0 {
+				defaults = defaultUnixEnv
+			}
+			s.Process.Env = replaceOrAppendEnvValues(defaults, s.Process.Env)
 			cmd := config.Cmd
 			cmd := config.Cmd
 			if len(args) > 0 {
 			if len(args) > 0 {
 				cmd = args
 				cmd = args
@@ -334,7 +360,7 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
 			// even if there is no specified user in the image config
 			// even if there is no specified user in the image config
 			return WithAdditionalGIDs("root")(ctx, client, c, s)
 			return WithAdditionalGIDs("root")(ctx, client, c, s)
 		} else if s.Windows != nil {
 		} else if s.Windows != nil {
-			s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env)
+			s.Process.Env = replaceOrAppendEnvValues(config.Env, s.Process.Env)
 			cmd := config.Cmd
 			cmd := config.Cmd
 			if len(args) > 0 {
 			if len(args) > 0 {
 				cmd = args
 				cmd = args
@@ -607,7 +633,7 @@ func WithUserID(uid uint32) SpecOpts {
 }
 }
 
 
 // WithUsername sets the correct UID and GID for the container
 // WithUsername sets the correct UID and GID for the container
-// based on the the image's /etc/passwd contents. If /etc/passwd
+// based on the image's /etc/passwd contents. If /etc/passwd
 // does not exist, or the username is not found in /etc/passwd,
 // does not exist, or the username is not found in /etc/passwd,
 // it returns error.
 // it returns error.
 func WithUsername(username string) SpecOpts {
 func WithUsername(username string) SpecOpts {
@@ -1139,3 +1165,85 @@ func WithAnnotations(annotations map[string]string) SpecOpts {
 		return nil
 		return nil
 	}
 	}
 }
 }
+
+// WithLinuxDevices adds the provided linux devices to the spec
+func WithLinuxDevices(devices []specs.LinuxDevice) SpecOpts {
+	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
+		setLinux(s)
+		s.Linux.Devices = append(s.Linux.Devices, devices...)
+		return nil
+	}
+}
+
+var ErrNotADevice = errors.New("not a device node")
+
+// WithLinuxDevice adds the device specified by path to the spec
+func WithLinuxDevice(path, permissions string) SpecOpts {
+	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
+		setLinux(s)
+		setResources(s)
+
+		dev, err := deviceFromPath(path, permissions)
+		if err != nil {
+			return err
+		}
+
+		s.Linux.Devices = append(s.Linux.Devices, *dev)
+
+		s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, specs.LinuxDeviceCgroup{
+			Type:   dev.Type,
+			Allow:  true,
+			Major:  &dev.Major,
+			Minor:  &dev.Minor,
+			Access: permissions,
+		})
+
+		return nil
+	}
+}
+
+// WithEnvFile adds environment variables from a file to the container's spec
+func WithEnvFile(path string) SpecOpts {
+	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
+		var vars []string
+		f, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer f.Close()
+
+		sc := bufio.NewScanner(f)
+		for sc.Scan() {
+			if sc.Err() != nil {
+				return sc.Err()
+			}
+			vars = append(vars, sc.Text())
+		}
+		return WithEnv(vars)(nil, nil, nil, s)
+	}
+}
+
+// ErrNoShmMount is returned when there is no /dev/shm mount specified in the config
+// and an Opts was trying to set a configuration value on the mount.
+var ErrNoShmMount = errors.New("no /dev/shm mount specified")
+
+// WithDevShmSize sets the size of the /dev/shm mount for the container.
+//
+// The size value is specified in kb, kilobytes.
+func WithDevShmSize(kb int64) SpecOpts {
+	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
+		for _, m := range s.Mounts {
+			if m.Source == "shm" && m.Type == "tmpfs" {
+				for i, o := range m.Options {
+					if strings.HasPrefix(o, "size=") {
+						m.Options[i] = fmt.Sprintf("size=%dk", kb)
+						return nil
+					}
+				}
+				m.Options = append(m.Options, fmt.Sprintf("size=%dk", kb))
+				return nil
+			}
+		}
+		return ErrNoShmMount
+	}
+}

+ 64 - 0
vendor/github.com/containerd/containerd/oci/spec_opts_linux.go

@@ -0,0 +1,64 @@
+// +build linux
+
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package oci
+
+import (
+	"os"
+
+	specs "github.com/opencontainers/runtime-spec/specs-go"
+	"golang.org/x/sys/unix"
+)
+
+func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) {
+	var stat unix.Stat_t
+	if err := unix.Lstat(path, &stat); err != nil {
+		return nil, err
+	}
+
+	var (
+		// The type is 32bit on mips.
+		devNumber = uint64(stat.Rdev) // nolint: unconvert
+		major     = unix.Major(devNumber)
+		minor     = unix.Minor(devNumber)
+	)
+	if major == 0 {
+		return nil, ErrNotADevice
+	}
+
+	var (
+		devType string
+		mode    = stat.Mode
+	)
+	switch {
+	case mode&unix.S_IFBLK == unix.S_IFBLK:
+		devType = "b"
+	case mode&unix.S_IFCHR == unix.S_IFCHR:
+		devType = "c"
+	}
+	fm := os.FileMode(mode)
+	return &specs.LinuxDevice{
+		Type:     devType,
+		Path:     path,
+		Major:    int64(major),
+		Minor:    int64(minor),
+		FileMode: &fm,
+		UID:      &stat.Uid,
+		GID:      &stat.Gid,
+	}, nil
+}

+ 63 - 0
vendor/github.com/containerd/containerd/oci/spec_opts_unix.go

@@ -0,0 +1,63 @@
+// +build !linux,!windows
+
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package oci
+
+import (
+	"os"
+
+	specs "github.com/opencontainers/runtime-spec/specs-go"
+	"golang.org/x/sys/unix"
+)
+
+func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) {
+	var stat unix.Stat_t
+	if err := unix.Lstat(path, &stat); err != nil {
+		return nil, err
+	}
+
+	var (
+		devNumber = uint64(stat.Rdev)
+		major     = unix.Major(devNumber)
+		minor     = unix.Minor(devNumber)
+	)
+	if major == 0 {
+		return nil, ErrNotADevice
+	}
+
+	var (
+		devType string
+		mode    = stat.Mode
+	)
+	switch {
+	case mode&unix.S_IFBLK == unix.S_IFBLK:
+		devType = "b"
+	case mode&unix.S_IFCHR == unix.S_IFCHR:
+		devType = "c"
+	}
+	fm := os.FileMode(mode)
+	return &specs.LinuxDevice{
+		Type:     devType,
+		Path:     path,
+		Major:    int64(major),
+		Minor:    int64(minor),
+		FileMode: &fm,
+		UID:      &stat.Uid,
+		GID:      &stat.Gid,
+	}, nil
+}

+ 5 - 0
vendor/github.com/containerd/containerd/oci/spec_opts_windows.go

@@ -23,6 +23,7 @@ import (
 
 
 	"github.com/containerd/containerd/containers"
 	"github.com/containerd/containerd/containers"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/pkg/errors"
 )
 )
 
 
 // WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the
 // WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the
@@ -65,3 +66,7 @@ func WithWindowNetworksAllowUnqualifiedDNSQuery() SpecOpts {
 		return nil
 		return nil
 	}
 	}
 }
 }
+
+func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) {
+	return nil, errors.New("device from path not supported on Windows")
+}

+ 13 - 1
vendor/github.com/containerd/containerd/pkg/dialer/dialer.go

@@ -17,6 +17,7 @@
 package dialer
 package dialer
 
 
 import (
 import (
+	"context"
 	"net"
 	"net"
 	"time"
 	"time"
 
 
@@ -28,8 +29,19 @@ type dialResult struct {
 	err error
 	err error
 }
 }
 
 
+// ContextDialer returns a GRPC net.Conn connected to the provided address
+func ContextDialer(ctx context.Context, address string) (net.Conn, error) {
+	if deadline, ok := ctx.Deadline(); ok {
+		return timeoutDialer(address, time.Until(deadline))
+	}
+	return timeoutDialer(address, 0)
+}
+
 // Dialer returns a GRPC net.Conn connected to the provided address
 // Dialer returns a GRPC net.Conn connected to the provided address
-func Dialer(address string, timeout time.Duration) (net.Conn, error) {
+// Deprecated: use ContextDialer and grpc.WithContextDialer.
+var Dialer = timeoutDialer
+
+func timeoutDialer(address string, timeout time.Duration) (net.Conn, error) {
 	var (
 	var (
 		stopC = make(chan struct{})
 		stopC = make(chan struct{})
 		synC  = make(chan *dialResult)
 		synC  = make(chan *dialResult)

+ 2 - 3
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/deleted_state.go → vendor/github.com/containerd/containerd/pkg/process/deleted_state.go

@@ -16,14 +16,13 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"
 
 
 	"github.com/containerd/console"
 	"github.com/containerd/console"
 	"github.com/containerd/containerd/errdefs"
 	"github.com/containerd/containerd/errdefs"
-	"github.com/containerd/containerd/runtime/proc"
 	google_protobuf "github.com/gogo/protobuf/types"
 	google_protobuf "github.com/gogo/protobuf/types"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
@@ -67,6 +66,6 @@ func (s *deletedState) SetExited(status int) {
 	// no op
 	// no op
 }
 }
 
 
-func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	return nil, errors.Errorf("cannot exec in a deleted state")
 	return nil, errors.Errorf("cannot exec in a deleted state")
 }
 }

+ 18 - 8
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/exec.go → vendor/github.com/containerd/containerd/pkg/process/exec.go

@@ -16,7 +16,7 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"
@@ -31,7 +31,8 @@ import (
 	"golang.org/x/sys/unix"
 	"golang.org/x/sys/unix"
 
 
 	"github.com/containerd/console"
 	"github.com/containerd/console"
-	"github.com/containerd/containerd/runtime/proc"
+	"github.com/containerd/containerd/errdefs"
+	"github.com/containerd/containerd/pkg/stdio"
 	"github.com/containerd/fifo"
 	"github.com/containerd/fifo"
 	runc "github.com/containerd/go-runc"
 	runc "github.com/containerd/go-runc"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
@@ -49,10 +50,10 @@ type execProcess struct {
 	io      *processIO
 	io      *processIO
 	status  int
 	status  int
 	exited  time.Time
 	exited  time.Time
-	pid     *safePid
+	pid     safePid
 	closers []io.Closer
 	closers []io.Closer
 	stdin   io.Closer
 	stdin   io.Closer
-	stdio   proc.Stdio
+	stdio   stdio.Stdio
 	path    string
 	path    string
 	spec    specs.Process
 	spec    specs.Process
 
 
@@ -95,6 +96,7 @@ func (e *execProcess) setExited(status int) {
 	e.status = status
 	e.status = status
 	e.exited = time.Now()
 	e.exited = time.Now()
 	e.parent.Platform.ShutdownConsole(context.Background(), e.console)
 	e.parent.Platform.ShutdownConsole(context.Background(), e.console)
+	e.pid.set(StoppedPID)
 	close(e.waitBlock)
 	close(e.waitBlock)
 }
 }
 
 
@@ -106,7 +108,7 @@ func (e *execProcess) Delete(ctx context.Context) error {
 }
 }
 
 
 func (e *execProcess) delete(ctx context.Context) error {
 func (e *execProcess) delete(ctx context.Context) error {
-	e.wg.Wait()
+	waitTimeout(ctx, &e.wg, 2*time.Second)
 	if e.io != nil {
 	if e.io != nil {
 		for _, c := range e.closers {
 		for _, c := range e.closers {
 			c.Close()
 			c.Close()
@@ -142,7 +144,12 @@ func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
 
 
 func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
 func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
 	pid := e.pid.get()
 	pid := e.pid.get()
-	if pid != 0 {
+	switch {
+	case pid == 0:
+		return errors.Wrap(errdefs.ErrFailedPrecondition, "process not created")
+	case pid < 0:
+		return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
+	default:
 		if err := unix.Kill(pid, syscall.Signal(sig)); err != nil {
 		if err := unix.Kill(pid, syscall.Signal(sig)); err != nil {
 			return errors.Wrapf(checkKillError(err), "exec kill error")
 			return errors.Wrapf(checkKillError(err), "exec kill error")
 		}
 		}
@@ -154,7 +161,7 @@ func (e *execProcess) Stdin() io.Closer {
 	return e.stdin
 	return e.stdin
 }
 }
 
 
-func (e *execProcess) Stdio() proc.Stdio {
+func (e *execProcess) Stdio() stdio.Stdio {
 	return e.stdio
 	return e.stdio
 }
 }
 
 
@@ -254,10 +261,13 @@ func (e *execProcess) Status(ctx context.Context) (string, error) {
 	}
 	}
 	e.mu.Lock()
 	e.mu.Lock()
 	defer e.mu.Unlock()
 	defer e.mu.Unlock()
-	// if we don't have a pid then the exec process has just been created
+	// if we don't have a pid(pid=0) then the exec process has just been created
 	if e.pid.get() == 0 {
 	if e.pid.get() == 0 {
 		return "created", nil
 		return "created", nil
 	}
 	}
+	if e.pid.get() == StoppedPID {
+		return "stopped", nil
+	}
 	// if we have a pid and it can be signaled, the process is running
 	// if we have a pid and it can be signaled, the process is running
 	if err := unix.Kill(e.pid.get(), 0); err == nil {
 	if err := unix.Kill(e.pid.get(), 0); err == nil {
 		return "running", nil
 		return "running", nil

+ 1 - 1
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/exec_state.go → vendor/github.com/containerd/containerd/pkg/process/exec_state.go

@@ -16,7 +16,7 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"

+ 18 - 22
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/init.go → vendor/github.com/containerd/containerd/pkg/process/init.go

@@ -16,7 +16,7 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"
@@ -33,7 +33,7 @@ import (
 	"github.com/containerd/console"
 	"github.com/containerd/console"
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/mount"
 	"github.com/containerd/containerd/mount"
-	"github.com/containerd/containerd/runtime/proc"
+	"github.com/containerd/containerd/pkg/stdio"
 	"github.com/containerd/fifo"
 	"github.com/containerd/fifo"
 	runc "github.com/containerd/go-runc"
 	runc "github.com/containerd/go-runc"
 	google_protobuf "github.com/gogo/protobuf/types"
 	google_protobuf "github.com/gogo/protobuf/types"
@@ -59,15 +59,15 @@ type Init struct {
 	id           string
 	id           string
 	Bundle       string
 	Bundle       string
 	console      console.Console
 	console      console.Console
-	Platform     proc.Platform
+	Platform     stdio.Platform
 	io           *processIO
 	io           *processIO
 	runtime      *runc.Runc
 	runtime      *runc.Runc
 	status       int
 	status       int
 	exited       time.Time
 	exited       time.Time
-	pid          int
+	pid          safePid
 	closers      []io.Closer
 	closers      []io.Closer
 	stdin        io.Closer
 	stdin        io.Closer
-	stdio        proc.Stdio
+	stdio        stdio.Stdio
 	Rootfs       string
 	Rootfs       string
 	IoUID        int
 	IoUID        int
 	IoGID        int
 	IoGID        int
@@ -93,7 +93,7 @@ func NewRunc(root, path, namespace, runtime, criu string, systemd bool) *runc.Ru
 }
 }
 
 
 // New returns a new process
 // New returns a new process
-func New(id string, runtime *runc.Runc, stdio proc.Stdio) *Init {
+func New(id string, runtime *runc.Runc, stdio stdio.Stdio) *Init {
 	p := &Init{
 	p := &Init{
 		id:        id,
 		id:        id,
 		runtime:   runtime,
 		runtime:   runtime,
@@ -113,6 +113,9 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
 		pio     *processIO
 		pio     *processIO
 		pidFile = newPidFile(p.Bundle)
 		pidFile = newPidFile(p.Bundle)
 	)
 	)
+	p.pid.Lock()
+	defer p.pid.Unlock()
+
 	if r.Terminal {
 	if r.Terminal {
 		if socket, err = runc.NewTempConsoleSocket(); err != nil {
 		if socket, err = runc.NewTempConsoleSocket(); err != nil {
 			return errors.Wrap(err, "failed to create OCI runtime console socket")
 			return errors.Wrap(err, "failed to create OCI runtime console socket")
@@ -167,7 +170,7 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
 	if err != nil {
 	if err != nil {
 		return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
 		return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
 	}
 	}
-	p.pid = pid
+	p.pid.pid = pid
 	return nil
 	return nil
 }
 }
 
 
@@ -213,7 +216,7 @@ func (p *Init) ID() string {
 
 
 // Pid of the process
 // Pid of the process
 func (p *Init) Pid() int {
 func (p *Init) Pid() int {
-	return p.pid
+	return p.pid.get()
 }
 }
 
 
 // ExitStatus of the process
 // ExitStatus of the process
@@ -272,6 +275,7 @@ func (p *Init) setExited(status int) {
 	p.exited = time.Now()
 	p.exited = time.Now()
 	p.status = status
 	p.status = status
 	p.Platform.ShutdownConsole(context.Background(), p.console)
 	p.Platform.ShutdownConsole(context.Background(), p.console)
+	p.pid.set(StoppedPID)
 	close(p.waitBlock)
 	close(p.waitBlock)
 }
 }
 
 
@@ -284,7 +288,7 @@ func (p *Init) Delete(ctx context.Context) error {
 }
 }
 
 
 func (p *Init) delete(ctx context.Context) error {
 func (p *Init) delete(ctx context.Context) error {
-	p.wg.Wait()
+	waitTimeout(ctx, &p.wg, 2*time.Second)
 	err := p.runtime.Delete(ctx, p.id, nil)
 	err := p.runtime.Delete(ctx, p.id, nil)
 	// ignore errors if a runtime has already deleted the process
 	// ignore errors if a runtime has already deleted the process
 	// but we still hold metadata and pipes
 	// but we still hold metadata and pipes
@@ -324,13 +328,6 @@ func (p *Init) Resize(ws console.WinSize) error {
 	return p.console.Resize(ws)
 	return p.console.Resize(ws)
 }
 }
 
 
-func (p *Init) resize(ws console.WinSize) error {
-	if p.console == nil {
-		return nil
-	}
-	return p.console.Resize(ws)
-}
-
 // Pause the init process and all its child processes
 // Pause the init process and all its child processes
 func (p *Init) Pause(ctx context.Context) error {
 func (p *Init) Pause(ctx context.Context) error {
 	p.mu.Lock()
 	p.mu.Lock()
@@ -384,7 +381,7 @@ func (p *Init) Runtime() *runc.Runc {
 }
 }
 
 
 // Exec returns a new child process
 // Exec returns a new child process
-func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	p.mu.Lock()
 	p.mu.Lock()
 	defer p.mu.Unlock()
 	defer p.mu.Unlock()
 
 
@@ -392,7 +389,7 @@ func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Proce
 }
 }
 
 
 // exec returns a new exec'd process
 // exec returns a new exec'd process
-func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	// process exec request
 	// process exec request
 	var spec specs.Process
 	var spec specs.Process
 	if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
 	if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
@@ -405,14 +402,13 @@ func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Proce
 		path:   path,
 		path:   path,
 		parent: p,
 		parent: p,
 		spec:   spec,
 		spec:   spec,
-		stdio: proc.Stdio{
+		stdio: stdio.Stdio{
 			Stdin:    r.Stdin,
 			Stdin:    r.Stdin,
 			Stdout:   r.Stdout,
 			Stdout:   r.Stdout,
 			Stderr:   r.Stderr,
 			Stderr:   r.Stderr,
 			Terminal: r.Terminal,
 			Terminal: r.Terminal,
 		},
 		},
 		waitBlock: make(chan struct{}),
 		waitBlock: make(chan struct{}),
-		pid:       &safePid{},
 	}
 	}
 	e.execState = &execCreatedState{p: e}
 	e.execState = &execCreatedState{p: e}
 	return e, nil
 	return e, nil
@@ -472,7 +468,7 @@ func (p *Init) update(ctx context.Context, r *google_protobuf.Any) error {
 }
 }
 
 
 // Stdio of the process
 // Stdio of the process
-func (p *Init) Stdio() proc.Stdio {
+func (p *Init) Stdio() stdio.Stdio {
 	return p.stdio
 	return p.stdio
 }
 }
 
 
@@ -492,7 +488,7 @@ func (p *Init) runtimeError(rErr error, msg string) error {
 	}
 	}
 }
 }
 
 
-func withConditionalIO(c proc.Stdio) runc.IOOpt {
+func withConditionalIO(c stdio.Stdio) runc.IOOpt {
 	return func(o *runc.IOOption) {
 	return func(o *runc.IOOption) {
 		o.OpenStdin = c.Stdin != ""
 		o.OpenStdin = c.Stdin != ""
 		o.OpenStdout = c.Stdout != ""
 		o.OpenStdout = c.Stdout != ""

+ 11 - 31
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/init_state.go → vendor/github.com/containerd/containerd/pkg/process/init_state.go

@@ -16,13 +16,11 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"
 
 
-	"github.com/containerd/console"
-	"github.com/containerd/containerd/runtime/proc"
 	runc "github.com/containerd/go-runc"
 	runc "github.com/containerd/go-runc"
 	google_protobuf "github.com/gogo/protobuf/types"
 	google_protobuf "github.com/gogo/protobuf/types"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -30,14 +28,13 @@ import (
 )
 )
 
 
 type initState interface {
 type initState interface {
-	Resize(console.WinSize) error
 	Start(context.Context) error
 	Start(context.Context) error
 	Delete(context.Context) error
 	Delete(context.Context) error
 	Pause(context.Context) error
 	Pause(context.Context) error
 	Resume(context.Context) error
 	Resume(context.Context) error
 	Update(context.Context, *google_protobuf.Any) error
 	Update(context.Context, *google_protobuf.Any) error
 	Checkpoint(context.Context, *CheckpointConfig) error
 	Checkpoint(context.Context, *CheckpointConfig) error
-	Exec(context.Context, string, *ExecConfig) (proc.Process, error)
+	Exec(context.Context, string, *ExecConfig) (Process, error)
 	Kill(context.Context, uint32, bool) error
 	Kill(context.Context, uint32, bool) error
 	SetExited(int)
 	SetExited(int)
 }
 }
@@ -76,10 +73,6 @@ func (s *createdState) Checkpoint(ctx context.Context, r *CheckpointConfig) erro
 	return errors.Errorf("cannot checkpoint a task in created state")
 	return errors.Errorf("cannot checkpoint a task in created state")
 }
 }
 
 
-func (s *createdState) Resize(ws console.WinSize) error {
-	return s.p.resize(ws)
-}
-
 func (s *createdState) Start(ctx context.Context) error {
 func (s *createdState) Start(ctx context.Context) error {
 	if err := s.p.start(ctx); err != nil {
 	if err := s.p.start(ctx); err != nil {
 		return err
 		return err
@@ -106,7 +99,7 @@ func (s *createdState) SetExited(status int) {
 	}
 	}
 }
 }
 
 
-func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	return s.p.exec(ctx, path, r)
 	return s.p.exec(ctx, path, r)
 }
 }
 
 
@@ -145,14 +138,13 @@ func (s *createdCheckpointState) Checkpoint(ctx context.Context, r *CheckpointCo
 	return errors.Errorf("cannot checkpoint a task in created state")
 	return errors.Errorf("cannot checkpoint a task in created state")
 }
 }
 
 
-func (s *createdCheckpointState) Resize(ws console.WinSize) error {
-	return s.p.resize(ws)
-}
-
 func (s *createdCheckpointState) Start(ctx context.Context) error {
 func (s *createdCheckpointState) Start(ctx context.Context) error {
 	p := s.p
 	p := s.p
 	sio := p.stdio
 	sio := p.stdio
 
 
+	p.pid.Lock()
+	defer p.pid.Unlock()
+
 	var (
 	var (
 		err    error
 		err    error
 		socket *runc.Socket
 		socket *runc.Socket
@@ -192,7 +184,7 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
 	if err != nil {
 	if err != nil {
 		return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
 		return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
 	}
 	}
-	p.pid = pid
+	p.pid.pid = pid
 	return s.transition("running")
 	return s.transition("running")
 }
 }
 
 
@@ -215,7 +207,7 @@ func (s *createdCheckpointState) SetExited(status int) {
 	}
 	}
 }
 }
 
 
-func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	return nil, errors.Errorf("cannot exec in a created state")
 	return nil, errors.Errorf("cannot exec in a created state")
 }
 }
 
 
@@ -255,10 +247,6 @@ func (s *runningState) Checkpoint(ctx context.Context, r *CheckpointConfig) erro
 	return s.p.checkpoint(ctx, r)
 	return s.p.checkpoint(ctx, r)
 }
 }
 
 
-func (s *runningState) Resize(ws console.WinSize) error {
-	return s.p.resize(ws)
-}
-
 func (s *runningState) Start(ctx context.Context) error {
 func (s *runningState) Start(ctx context.Context) error {
 	return errors.Errorf("cannot start a running process")
 	return errors.Errorf("cannot start a running process")
 }
 }
@@ -279,7 +267,7 @@ func (s *runningState) SetExited(status int) {
 	}
 	}
 }
 }
 
 
-func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	return s.p.exec(ctx, path, r)
 	return s.p.exec(ctx, path, r)
 }
 }
 
 
@@ -319,10 +307,6 @@ func (s *pausedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error
 	return s.p.checkpoint(ctx, r)
 	return s.p.checkpoint(ctx, r)
 }
 }
 
 
-func (s *pausedState) Resize(ws console.WinSize) error {
-	return s.p.resize(ws)
-}
-
 func (s *pausedState) Start(ctx context.Context) error {
 func (s *pausedState) Start(ctx context.Context) error {
 	return errors.Errorf("cannot start a paused process")
 	return errors.Errorf("cannot start a paused process")
 }
 }
@@ -347,7 +331,7 @@ func (s *pausedState) SetExited(status int) {
 	}
 	}
 }
 }
 
 
-func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	return nil, errors.Errorf("cannot exec in a paused state")
 	return nil, errors.Errorf("cannot exec in a paused state")
 }
 }
 
 
@@ -381,10 +365,6 @@ func (s *stoppedState) Checkpoint(ctx context.Context, r *CheckpointConfig) erro
 	return errors.Errorf("cannot checkpoint a stopped container")
 	return errors.Errorf("cannot checkpoint a stopped container")
 }
 }
 
 
-func (s *stoppedState) Resize(ws console.WinSize) error {
-	return errors.Errorf("cannot resize a stopped container")
-}
-
 func (s *stoppedState) Start(ctx context.Context) error {
 func (s *stoppedState) Start(ctx context.Context) error {
 	return errors.Errorf("cannot start a stopped process")
 	return errors.Errorf("cannot start a stopped process")
 }
 }
@@ -404,6 +384,6 @@ func (s *stoppedState) SetExited(status int) {
 	// no op
 	// no op
 }
 }
 
 
-func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
+func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
 	return nil, errors.Errorf("cannot exec in a stopped state")
 	return nil, errors.Errorf("cannot exec in a stopped state")
 }
 }

+ 16 - 12
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/io.go → vendor/github.com/containerd/containerd/pkg/process/io.go

@@ -16,7 +16,7 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"
@@ -32,7 +32,7 @@ import (
 
 
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/log"
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/namespaces"
-	"github.com/containerd/containerd/runtime/proc"
+	"github.com/containerd/containerd/pkg/stdio"
 	"github.com/containerd/fifo"
 	"github.com/containerd/fifo"
 	runc "github.com/containerd/go-runc"
 	runc "github.com/containerd/go-runc"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -50,7 +50,7 @@ type processIO struct {
 
 
 	uri   *url.URL
 	uri   *url.URL
 	copy  bool
 	copy  bool
-	stdio proc.Stdio
+	stdio stdio.Stdio
 }
 }
 
 
 func (p *processIO) Close() error {
 func (p *processIO) Close() error {
@@ -76,7 +76,7 @@ func (p *processIO) Copy(ctx context.Context, wg *sync.WaitGroup) error {
 	return nil
 	return nil
 }
 }
 
 
-func createIO(ctx context.Context, id string, ioUID, ioGID int, stdio proc.Stdio) (*processIO, error) {
+func createIO(ctx context.Context, id string, ioUID, ioGID int, stdio stdio.Stdio) (*processIO, error) {
 	pio := &processIO{
 	pio := &processIO{
 		stdio: stdio,
 		stdio: stdio,
 	}
 	}
@@ -101,17 +101,20 @@ func createIO(ctx context.Context, id string, ioUID, ioGID int, stdio proc.Stdio
 		pio.copy = true
 		pio.copy = true
 		pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio))
 		pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio))
 	case "binary":
 	case "binary":
-		pio.io, err = newBinaryIO(ctx, id, u)
+		pio.io, err = NewBinaryIO(ctx, id, u)
 	case "file":
 	case "file":
-		if err := os.MkdirAll(filepath.Dir(u.Host), 0755); err != nil {
+		filePath := u.Path
+		if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		var f *os.File
 		var f *os.File
-		f, err = os.OpenFile(u.Host, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+		f, err = os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		f.Close()
 		f.Close()
+		pio.stdio.Stdout = filePath
+		pio.stdio.Stderr = filePath
 		pio.copy = true
 		pio.copy = true
 		pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio))
 		pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio))
 	default:
 	default:
@@ -179,10 +182,10 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
 		)
 		)
 		if ok {
 		if ok {
 			if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil {
 			if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil {
-				return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
+				return errors.Wrapf(err, "containerd-shim: opening w/o fifo %q failed", i.name)
 			}
 			}
 			if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil {
 			if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil {
-				return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
+				return errors.Wrapf(err, "containerd-shim: opening r/o fifo %q failed", i.name)
 			}
 			}
 		} else {
 		} else {
 			if sameFile != nil {
 			if sameFile != nil {
@@ -191,7 +194,7 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
 				continue
 				continue
 			}
 			}
 			if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil {
 			if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil {
-				return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
+				return errors.Wrapf(err, "containerd-shim: opening file %q failed", i.name)
 			}
 			}
 			if stdout == stderr {
 			if stdout == stderr {
 				sameFile = &countingWriteCloser{
 				sameFile = &countingWriteCloser{
@@ -251,7 +254,8 @@ func isFifo(path string) (bool, error) {
 	return false, nil
 	return false, nil
 }
 }
 
 
-func newBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error) {
+// NewBinaryIO runs a custom binary process for pluggable shim logging
+func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error) {
 	ns, err := namespaces.NamespaceRequired(ctx)
 	ns, err := namespaces.NamespaceRequired(ctx)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -264,7 +268,7 @@ func newBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error)
 		}
 		}
 	}
 	}
 	ctx, cancel := context.WithCancel(ctx)
 	ctx, cancel := context.WithCancel(ctx)
-	cmd := exec.CommandContext(ctx, uri.Host, args...)
+	cmd := exec.CommandContext(ctx, uri.Path, args...)
 	cmd.Env = append(cmd.Env,
 	cmd.Env = append(cmd.Env,
 		"CONTAINER_ID="+id,
 		"CONTAINER_ID="+id,
 		"CONTAINER_NAMESPACE="+ns,
 		"CONTAINER_NAMESPACE="+ns,

+ 3 - 25
vendor/github.com/containerd/containerd/runtime/proc/proc.go → vendor/github.com/containerd/containerd/pkg/process/process.go

@@ -14,30 +14,17 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	"context"
 	"context"
 	"io"
 	"io"
-	"sync"
 	"time"
 	"time"
 
 
 	"github.com/containerd/console"
 	"github.com/containerd/console"
+	"github.com/containerd/containerd/pkg/stdio"
 )
 )
 
 
-// Stdio of a process
-type Stdio struct {
-	Stdin    string
-	Stdout   string
-	Stderr   string
-	Terminal bool
-}
-
-// IsNull returns true if the stdio is not defined
-func (s Stdio) IsNull() bool {
-	return s.Stdin == "" && s.Stdout == "" && s.Stderr == ""
-}
-
 // Process on a system
 // Process on a system
 type Process interface {
 type Process interface {
 	// ID returns the id for the process
 	// ID returns the id for the process
@@ -51,7 +38,7 @@ type Process interface {
 	// Stdin returns the process STDIN
 	// Stdin returns the process STDIN
 	Stdin() io.Closer
 	Stdin() io.Closer
 	// Stdio returns io information for the container
 	// Stdio returns io information for the container
-	Stdio() Stdio
+	Stdio() stdio.Stdio
 	// Status returns the process status
 	// Status returns the process status
 	Status(context.Context) (string, error)
 	Status(context.Context) (string, error)
 	// Wait blocks until the process has exited
 	// Wait blocks until the process has exited
@@ -67,12 +54,3 @@ type Process interface {
 	// SetExited sets the exit status for the process
 	// SetExited sets the exit status for the process
 	SetExited(status int)
 	SetExited(status int)
 }
 }
-
-// Platform handles platform-specific behavior that may differs across
-// platform implementations
-type Platform interface {
-	CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string,
-		wg *sync.WaitGroup) (console.Console, error)
-	ShutdownConsole(ctx context.Context, console console.Console) error
-	Close() error
-}

+ 1 - 1
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/types.go → vendor/github.com/containerd/containerd/pkg/process/types.go

@@ -14,7 +14,7 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
 	google_protobuf "github.com/gogo/protobuf/types"
 	google_protobuf "github.com/gogo/protobuf/types"

+ 53 - 4
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/utils.go → vendor/github.com/containerd/containerd/pkg/process/utils.go

@@ -16,9 +16,10 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package proc
+package process
 
 
 import (
 import (
+	"context"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
@@ -34,6 +35,15 @@ import (
 	"golang.org/x/sys/unix"
 	"golang.org/x/sys/unix"
 )
 )
 
 
+const (
+	// RuncRoot is the path to the root runc state directory
+	RuncRoot = "/run/containerd/runc"
+	// StoppedPID is the pid assigned after a container has run and stopped
+	StoppedPID = -1
+	// InitPidFile name of the file that contains the init pid
+	InitPidFile = "init.pid"
+)
+
 // safePid is a thread safe wrapper for pid.
 // safePid is a thread safe wrapper for pid.
 type safePid struct {
 type safePid struct {
 	sync.Mutex
 	sync.Mutex
@@ -46,6 +56,12 @@ func (s *safePid) get() int {
 	return s.pid
 	return s.pid
 }
 }
 
 
+func (s *safePid) set(pid int) {
+	s.Lock()
+	s.pid = pid
+	s.Unlock()
+}
+
 // TODO(mlaventure): move to runc package?
 // TODO(mlaventure): move to runc package?
 func getLastRuntimeError(r *runc.Runc) (string, error) {
 func getLastRuntimeError(r *runc.Runc) (string, error) {
 	if r.Log == "" {
 	if r.Log == "" {
@@ -56,6 +72,7 @@ func getLastRuntimeError(r *runc.Runc) (string, error) {
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
+	defer f.Close()
 
 
 	var (
 	var (
 		errMsg string
 		errMsg string
@@ -110,15 +127,13 @@ func checkKillError(err error) error {
 	}
 	}
 	if strings.Contains(err.Error(), "os: process already finished") ||
 	if strings.Contains(err.Error(), "os: process already finished") ||
 		strings.Contains(err.Error(), "container not running") ||
 		strings.Contains(err.Error(), "container not running") ||
+		strings.Contains(strings.ToLower(err.Error()), "no such process") ||
 		err == unix.ESRCH {
 		err == unix.ESRCH {
 		return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
 		return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
 	}
 	}
 	return errors.Wrapf(err, "unknown error after kill")
 	return errors.Wrapf(err, "unknown error after kill")
 }
 }
 
 
-// InitPidFile name of the file that contains the init pid
-const InitPidFile = "init.pid"
-
 func newPidFile(bundle string) *pidFile {
 func newPidFile(bundle string) *pidFile {
 	return &pidFile{
 	return &pidFile{
 		path: filepath.Join(bundle, InitPidFile),
 		path: filepath.Join(bundle, InitPidFile),
@@ -142,3 +157,37 @@ func (p *pidFile) Path() string {
 func (p *pidFile) Read() (int, error) {
 func (p *pidFile) Read() (int, error) {
 	return runc.ReadPidFile(p.path)
 	return runc.ReadPidFile(p.path)
 }
 }
+
+// waitTimeout handles waiting on a waitgroup with a specified timeout.
+// this is commonly used for waiting on IO to finish after a process has exited
+func waitTimeout(ctx context.Context, wg *sync.WaitGroup, timeout time.Duration) error {
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+	done := make(chan struct{}, 1)
+	go func() {
+		wg.Wait()
+		close(done)
+	}()
+	select {
+	case <-done:
+		return nil
+	case <-ctx.Done():
+		return ctx.Err()
+	}
+}
+
+func stateName(v interface{}) string {
+	switch v.(type) {
+	case *runningState, *execRunningState:
+		return "running"
+	case *createdState, *execCreatedState, *createdCheckpointState:
+		return "created"
+	case *pausedState:
+		return "paused"
+	case *deletedState:
+		return "deleted"
+	case *stoppedState:
+		return "stopped"
+	}
+	panic(errors.Errorf("invalid state %v", v))
+}

+ 33 - 0
vendor/github.com/containerd/containerd/pkg/stdio/platform.go

@@ -0,0 +1,33 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package stdio
+
+import (
+	"context"
+	"sync"
+
+	"github.com/containerd/console"
+)
+
+// Platform handles platform-specific behavior that may differs across
+// platform implementations
+type Platform interface {
+	CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string,
+		wg *sync.WaitGroup) (console.Console, error)
+	ShutdownConsole(ctx context.Context, console console.Console) error
+	Close() error
+}

+ 11 - 9
vendor/github.com/containerd/continuity/resource_windows.go → vendor/github.com/containerd/containerd/pkg/stdio/stdio.go

@@ -14,15 +14,17 @@
    limitations under the License.
    limitations under the License.
 */
 */
 
 
-package continuity
+package stdio
 
 
-import "os"
+// Stdio of a process
+type Stdio struct {
+	Stdin    string
+	Stdout   string
+	Stderr   string
+	Terminal bool
+}
 
 
-// newBaseResource returns a *resource, populated with data from p and fi,
-// where p will be populated directly.
-func newBaseResource(p string, fi os.FileInfo) (*resource, error) {
-	return &resource{
-		paths: []string{p},
-		mode:  fi.Mode(),
-	}, nil
+// IsNull returns true if the stdio is not defined
+func (s Stdio) IsNull() bool {
+	return s.Stdin == "" && s.Stdout == "" && s.Stderr == ""
 }
 }

+ 37 - 0
vendor/github.com/containerd/containerd/platforms/compare.go

@@ -29,11 +29,48 @@ type MatchComparer interface {
 // Only returns a match comparer for a single platform
 // Only returns a match comparer for a single platform
 // using default resolution logic for the platform.
 // using default resolution logic for the platform.
 //
 //
+// For ARMv8, will also match ARMv7, ARMv6 and ARMv5 (for 32bit runtimes)
 // For ARMv7, will also match ARMv6 and ARMv5
 // For ARMv7, will also match ARMv6 and ARMv5
 // For ARMv6, will also match ARMv5
 // For ARMv6, will also match ARMv5
 func Only(platform specs.Platform) MatchComparer {
 func Only(platform specs.Platform) MatchComparer {
 	platform = Normalize(platform)
 	platform = Normalize(platform)
 	if platform.Architecture == "arm" {
 	if platform.Architecture == "arm" {
+		if platform.Variant == "v8" {
+			return orderedPlatformComparer{
+				matchers: []Matcher{
+					&matcher{
+						Platform: platform,
+					},
+					&matcher{
+						Platform: specs.Platform{
+							Architecture: platform.Architecture,
+							OS:           platform.OS,
+							OSVersion:    platform.OSVersion,
+							OSFeatures:   platform.OSFeatures,
+							Variant:      "v7",
+						},
+					},
+					&matcher{
+						Platform: specs.Platform{
+							Architecture: platform.Architecture,
+							OS:           platform.OS,
+							OSVersion:    platform.OSVersion,
+							OSFeatures:   platform.OSFeatures,
+							Variant:      "v6",
+						},
+					},
+					&matcher{
+						Platform: specs.Platform{
+							Architecture: platform.Architecture,
+							OS:           platform.OS,
+							OSVersion:    platform.OSVersion,
+							OSFeatures:   platform.OSFeatures,
+							Variant:      "v5",
+						},
+					},
+				},
+			}
+		}
 		if platform.Variant == "v7" {
 		if platform.Variant == "v7" {
 			return orderedPlatformComparer{
 			return orderedPlatformComparer{
 				matchers: []Matcher{
 				matchers: []Matcher{

+ 1 - 1
vendor/github.com/containerd/containerd/platforms/cpuinfo.go

@@ -97,7 +97,7 @@ func getCPUVariant() string {
 	}
 	}
 
 
 	switch variant {
 	switch variant {
-	case "8":
+	case "8", "AArch64":
 		variant = "v8"
 		variant = "v8"
 	case "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
 	case "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
 		variant = "v7"
 		variant = "v7"

Some files were not shown because too many files changed in this diff