commit
56c6ea2827
|
@ -69,7 +69,7 @@ Different versions of the example scripts show different ways of describing the
|
||||||
|
|
||||||
#### Supported runc version
|
#### Supported runc version
|
||||||
|
|
||||||
During development buildkit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/8095244c26fa2daaef850be862e5b1b56d7cec66/RUNC.md) for more information.
|
During development buildkit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/d1e11f17ec7b325f89608dd46c128300b8727d50/RUNC.md) for more information.
|
||||||
|
|
||||||
|
|
||||||
#### Contributing
|
#### Contributing
|
||||||
|
|
|
@ -186,7 +186,7 @@ func (w *bufferedWriter) Digest() digest.Digest {
|
||||||
return w.digester.Digest()
|
return w.digester.Digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *bufferedWriter) Commit(size int64, expected digest.Digest, opt ...content.Opt) error {
|
func (w *bufferedWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opt ...content.Opt) error {
|
||||||
if w.buffer == nil {
|
if w.buffer == nil {
|
||||||
return errors.Errorf("can't commit already committed or closed")
|
return errors.Errorf("can't commit already committed or closed")
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ func NewContainerd(root, address string) (*Controller, error) {
|
||||||
func newContainerdPullDeps(client *containerd.Client) *pullDeps {
|
func newContainerdPullDeps(client *containerd.Client) *pullDeps {
|
||||||
diff := client.DiffService()
|
diff := client.DiffService()
|
||||||
return &pullDeps{
|
return &pullDeps{
|
||||||
Snapshotter: client.SnapshotService(""),
|
Snapshotter: client.SnapshotService(containerd.DefaultSnapshotter),
|
||||||
ContentStore: client.ContentStore(),
|
ContentStore: client.ContentStore(),
|
||||||
Applier: diff,
|
Applier: diff,
|
||||||
Differ: diff,
|
Differ: diff,
|
||||||
|
|
|
@ -55,7 +55,7 @@ func newStandalonePullDeps(root string) (*pullDeps, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
differ, err := differ.NewBaseDiff(c)
|
df, err := differ.NewWalkingDiff(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,8 @@ func newStandalonePullDeps(root string) (*pullDeps, error) {
|
||||||
return &pullDeps{
|
return &pullDeps{
|
||||||
Snapshotter: &nsSnapshotter{s},
|
Snapshotter: &nsSnapshotter{s},
|
||||||
ContentStore: c,
|
ContentStore: c,
|
||||||
Applier: differ,
|
Applier: df,
|
||||||
Differ: differ,
|
Differ: df,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,9 @@ func TestControl(t *testing.T) {
|
||||||
|
|
||||||
err = w.Exec(ctx, meta, snap, nil, nil, &nopCloser{stderr})
|
err = w.Exec(ctx, meta, snap, nil, nil, &nopCloser{stderr})
|
||||||
assert.Error(t, err) // Read-only root
|
assert.Error(t, err) // Read-only root
|
||||||
assert.Contains(t, stderr.String(), "Read-only file system")
|
// typical error is like `mkdir /.../rootfs/proc: read-only file system`.
|
||||||
|
// make sure the error is caused before running `echo foo > /bar`.
|
||||||
|
assert.Contains(t, stderr.String(), "read-only file system")
|
||||||
|
|
||||||
root, err := cm.New(ctx, snap)
|
root, err := cm.New(ctx, snap)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -115,7 +115,7 @@ func copyFrom(src llb.State, srcPath, destPath string) llb.StateOption {
|
||||||
// copy copies files between 2 states using cp until there is no copyOp
|
// copy copies files between 2 states using cp until there is no copyOp
|
||||||
func copy(src llb.State, srcPath string, dest llb.State, destPath string) llb.State {
|
func copy(src llb.State, srcPath string, dest llb.State, destPath string) llb.State {
|
||||||
cpImage := llb.Image("docker.io/library/alpine:latest")
|
cpImage := llb.Image("docker.io/library/alpine:latest")
|
||||||
cp := cpImage.Run(llb.Shlexf("cp -a /src%s /dest%s", srcPath, destPath), llb.ReadonlyRootFS)
|
cp := cpImage.Run(llb.Shlexf("cp -a /src%s /dest%s", srcPath, destPath))
|
||||||
cp.AddMount("/src", src, llb.Readonly)
|
cp.AddMount("/src", src, llb.Readonly)
|
||||||
return cp.AddMount("/dest", dest)
|
return cp.AddMount("/dest", dest)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
ARG RUNC_VERSION=e775f0fba3ea329b8b766451c892c41a3d49594d
|
ARG RUNC_VERSION=e775f0fba3ea329b8b766451c892c41a3d49594d
|
||||||
ARG CONTAINERD_VERSION=8095244c26fa2daaef850be862e5b1b56d7cec66
|
ARG CONTAINERD_VERSION=d1e11f17ec7b325f89608dd46c128300b8727d50
|
||||||
|
|
||||||
FROM golang:1.8-alpine AS gobuild-base
|
FROM golang:1.8-alpine AS gobuild-base
|
||||||
RUN apk add --no-cache g++ linux-headers
|
RUN apk add --no-cache g++ linux-headers
|
||||||
|
|
|
@ -78,7 +78,7 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
|
||||||
mountable = ref
|
mountable = ref
|
||||||
}
|
}
|
||||||
if m.Output != pb.SkipOutput {
|
if m.Output != pb.SkipOutput {
|
||||||
if m.Readonly && ref != nil {
|
if m.Readonly && ref != nil && m.Dest != pb.RootMount { // exclude read-only rootfs
|
||||||
outputs = append(outputs, newSharedRef(ref).Clone())
|
outputs = append(outputs, newSharedRef(ref).Clone())
|
||||||
} else {
|
} else {
|
||||||
active, err := e.cm.New(ctx, ref, cache.WithDescription(fmt.Sprintf("mount %s from exec %s", m.Dest, strings.Join(e.op.Meta.Args, " ")))) // TODO: should be method
|
active, err := e.cm.New(ctx, ref, cache.WithDescription(fmt.Sprintf("mount %s from exec %s", m.Dest, strings.Join(e.op.Meta.Args, " ")))) // TODO: should be method
|
||||||
|
|
|
@ -2,7 +2,6 @@ package containerimage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gocontext "context"
|
gocontext "context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -12,6 +11,7 @@ import (
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
"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/remotes"
|
"github.com/containerd/containerd/remotes"
|
||||||
"github.com/containerd/containerd/remotes/docker"
|
"github.com/containerd/containerd/remotes/docker"
|
||||||
"github.com/containerd/containerd/rootfs"
|
"github.com/containerd/containerd/rootfs"
|
||||||
|
@ -213,21 +213,17 @@ func (is *imageSource) fillBlobMapping(ctx context.Context, layers []rootfs.Laye
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLayers(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]rootfs.Layer, error) {
|
func getLayers(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]rootfs.Layer, error) {
|
||||||
p, err := content.ReadBlob(ctx, provider, desc.Digest)
|
manifest, err := images.Manifest(ctx, provider, desc, platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to read manifest blob")
|
return nil, errors.WithStack(err)
|
||||||
}
|
|
||||||
var manifest ocispec.Manifest
|
|
||||||
if err := json.Unmarshal(p, &manifest); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to unmarshal manifest")
|
|
||||||
}
|
}
|
||||||
image := images.Image{Target: desc}
|
image := images.Image{Target: desc}
|
||||||
diffIDs, err := image.RootFS(ctx, provider)
|
diffIDs, err := image.RootFS(ctx, provider, platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to resolve rootfs")
|
return nil, errors.Wrap(err, "failed to resolve rootfs")
|
||||||
}
|
}
|
||||||
if len(diffIDs) != len(manifest.Layers) {
|
if len(diffIDs) != len(manifest.Layers) {
|
||||||
return nil, errors.Errorf("mismatched image rootfs and manifest layers")
|
return nil, errors.Errorf("mismatched image rootfs and manifest layers %+v %+v", diffIDs, manifest.Layers)
|
||||||
}
|
}
|
||||||
layers := make([]rootfs.Layer, len(diffIDs))
|
layers := make([]rootfs.Layer, len(diffIDs))
|
||||||
for i := range diffIDs {
|
for i := range diffIDs {
|
||||||
|
|
|
@ -35,7 +35,7 @@ func Config(ctx context.Context, ref string, resolver remotes.Resolver, ingester
|
||||||
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
|
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config, err := images.Config(ctx, ingester, desc)
|
config, err := images.Config(ctx, ingester, desc, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ github.com/davecgh/go-spew v1.1.0
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib v1.0.0
|
||||||
golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f
|
golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f
|
||||||
|
|
||||||
github.com/containerd/containerd 8095244c26fa2daaef850be862e5b1b56d7cec66
|
github.com/containerd/containerd d1e11f17ec7b325f89608dd46c128300b8727d50
|
||||||
golang.org/x/sync f52d1811a62927559de87708c8913c1650ce4f26
|
golang.org/x/sync f52d1811a62927559de87708c8913c1650ce4f26
|
||||||
github.com/sirupsen/logrus v1.0.0
|
github.com/sirupsen/logrus v1.0.0
|
||||||
google.golang.org/grpc v1.3.0
|
google.golang.org/grpc v1.3.0
|
||||||
|
|
|
@ -60,25 +60,25 @@ image, err := client.Pull(context, "docker.io/library/redis:latest")
|
||||||
err := client.Push(context, "docker.io/library/redis:latest", image.Target())
|
err := client.Push(context, "docker.io/library/redis:latest", image.Target())
|
||||||
```
|
```
|
||||||
|
|
||||||
### OCI Runtime Specification
|
|
||||||
|
|
||||||
containerd fully supports the OCI runtime specification for running containers. We have built in functions to help you generate runtime specifications based on images as well as custom parameters.
|
|
||||||
|
|
||||||
```go
|
|
||||||
spec, err := containerd.GenerateSpec(containerd.WithImageConfig(context, image))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Containers
|
### Containers
|
||||||
|
|
||||||
In containerd, a container is a metadata object. Resources such as an OCI runtime specification, image, root filesystem, and other metadata can be attached to a container.
|
In containerd, a container is a metadata object. Resources such as an OCI runtime specification, image, root filesystem, and other metadata can be attached to a container.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
redis, err := client.NewContainer(context, "redis-master",
|
redis, err := client.NewContainer(context, "redis-master")
|
||||||
containerd.WithSpec(spec),
|
|
||||||
)
|
|
||||||
defer redis.Delete(context)
|
defer redis.Delete(context)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### OCI Runtime Specification
|
||||||
|
|
||||||
|
containerd fully supports the OCI runtime specification for running containers. We have built in functions to help you generate runtime specifications based on images as well as custom parameters.
|
||||||
|
|
||||||
|
You can specify options when creating a container about how to modify the specification.
|
||||||
|
|
||||||
|
```go
|
||||||
|
redis, err := client.NewContainer(context, "redis-master", containerd.WithNewSpec(containerd.WithImageConfig(image)))
|
||||||
|
```
|
||||||
|
|
||||||
## Root Filesystems
|
## Root Filesystems
|
||||||
|
|
||||||
containerd allows you to use overlay or snapshot filesystems with your containers. It comes with builtin support for overlayfs and btrfs.
|
containerd allows you to use overlay or snapshot filesystems with your containers. It comes with builtin support for overlayfs and btrfs.
|
||||||
|
@ -89,16 +89,17 @@ image, err := client.Pull(context, "docker.io/library/redis:latest", containerd.
|
||||||
|
|
||||||
// allocate a new RW root filesystem for a container based on the image
|
// allocate a new RW root filesystem for a container based on the image
|
||||||
redis, err := client.NewContainer(context, "redis-master",
|
redis, err := client.NewContainer(context, "redis-master",
|
||||||
containerd.WithSpec(spec),
|
|
||||||
containerd.WithNewSnapshot("redis-rootfs", image),
|
containerd.WithNewSnapshot("redis-rootfs", image),
|
||||||
|
containerd.WithNewSpec(containerd.WithImageConfig(image)),
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// use a readonly filesystem with multiple containers
|
// use a readonly filesystem with multiple containers
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
id := fmt.Sprintf("id-%s", i)
|
id := fmt.Sprintf("id-%s", i)
|
||||||
container, err := client.NewContainer(ctx, id,
|
container, err := client.NewContainer(ctx, id,
|
||||||
containerd.WithSpec(spec),
|
|
||||||
containerd.WithNewSnapshotView(id, image),
|
containerd.WithNewSnapshotView(id, image),
|
||||||
|
containerd.WithNewSpec(containerd.WithImageConfig(image)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -191,6 +192,11 @@ For sync communication we have a community slack with a #containerd channel that
|
||||||
|
|
||||||
**Slack:** https://dockr.ly/community
|
**Slack:** https://dockr.ly/community
|
||||||
|
|
||||||
|
### Reporting security issues
|
||||||
|
|
||||||
|
__If you are reporting a security issue, please follow the responsible
|
||||||
|
disclosure guidelines and reach out discreetly at containerd-security@googlegroups.com__.
|
||||||
|
|
||||||
## Copyright and license
|
## Copyright and license
|
||||||
|
|
||||||
Copyright ©2016-2017 Docker, Inc. All rights reserved, except as follows. Code
|
Copyright ©2016-2017 Docker, Inc. All rights reserved, except as follows. Code
|
||||||
|
|
115
vendor/github.com/containerd/containerd/api/services/containers/v1/containers.pb.go
generated
vendored
115
vendor/github.com/containerd/containerd/api/services/containers/v1/containers.pb.go
generated
vendored
|
@ -79,15 +79,17 @@ type Container struct {
|
||||||
Spec *google_protobuf1.Any `protobuf:"bytes,5,opt,name=spec" json:"spec,omitempty"`
|
Spec *google_protobuf1.Any `protobuf:"bytes,5,opt,name=spec" json:"spec,omitempty"`
|
||||||
// Snapshotter specifies the snapshotter name used for rootfs
|
// Snapshotter specifies the snapshotter name used for rootfs
|
||||||
Snapshotter string `protobuf:"bytes,6,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"`
|
Snapshotter string `protobuf:"bytes,6,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"`
|
||||||
// RootFS specifies the snapshot key to use for the container's root
|
// SnapshotKey specifies the snapshot key to use for the container's root
|
||||||
// filesystem. When starting a task from this container, a caller should
|
// filesystem. When starting a task from this container, a caller should
|
||||||
// look up the mounts from the snapshot service and include those on the
|
// look up the mounts from the snapshot service and include those on the
|
||||||
// task create request.
|
// task create request.
|
||||||
//
|
//
|
||||||
// Snapshots referenced in this field will not be garbage collected.
|
// Snapshots referenced in this field will not be garbage collected.
|
||||||
//
|
//
|
||||||
|
// This field is set to empty when the rootfs is not a snapshot.
|
||||||
|
//
|
||||||
// This field may be updated.
|
// This field may be updated.
|
||||||
RootFS string `protobuf:"bytes,7,opt,name=rootfs,proto3" json:"rootfs,omitempty"`
|
SnapshotKey string `protobuf:"bytes,7,opt,name=snapshot_key,json=snapshotKey,proto3" json:"snapshot_key,omitempty"`
|
||||||
// CreatedAt is the time the container was first created.
|
// CreatedAt is the time the container was first created.
|
||||||
CreatedAt time.Time `protobuf:"bytes,8,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
|
CreatedAt time.Time `protobuf:"bytes,8,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
|
||||||
// UpdatedAt is the last time the container was mutated.
|
// UpdatedAt is the last time the container was mutated.
|
||||||
|
@ -494,11 +496,11 @@ func (m *Container) MarshalTo(dAtA []byte) (int, error) {
|
||||||
i = encodeVarintContainers(dAtA, i, uint64(len(m.Snapshotter)))
|
i = encodeVarintContainers(dAtA, i, uint64(len(m.Snapshotter)))
|
||||||
i += copy(dAtA[i:], m.Snapshotter)
|
i += copy(dAtA[i:], m.Snapshotter)
|
||||||
}
|
}
|
||||||
if len(m.RootFS) > 0 {
|
if len(m.SnapshotKey) > 0 {
|
||||||
dAtA[i] = 0x3a
|
dAtA[i] = 0x3a
|
||||||
i++
|
i++
|
||||||
i = encodeVarintContainers(dAtA, i, uint64(len(m.RootFS)))
|
i = encodeVarintContainers(dAtA, i, uint64(len(m.SnapshotKey)))
|
||||||
i += copy(dAtA[i:], m.RootFS)
|
i += copy(dAtA[i:], m.SnapshotKey)
|
||||||
}
|
}
|
||||||
dAtA[i] = 0x42
|
dAtA[i] = 0x42
|
||||||
i++
|
i++
|
||||||
|
@ -862,7 +864,7 @@ func (m *Container) Size() (n int) {
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
n += 1 + l + sovContainers(uint64(l))
|
n += 1 + l + sovContainers(uint64(l))
|
||||||
}
|
}
|
||||||
l = len(m.RootFS)
|
l = len(m.SnapshotKey)
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
n += 1 + l + sovContainers(uint64(l))
|
n += 1 + l + sovContainers(uint64(l))
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1011,7 @@ func (this *Container) String() string {
|
||||||
`Runtime:` + strings.Replace(fmt.Sprintf("%v", this.Runtime), "Container_Runtime", "Container_Runtime", 1) + `,`,
|
`Runtime:` + strings.Replace(fmt.Sprintf("%v", this.Runtime), "Container_Runtime", "Container_Runtime", 1) + `,`,
|
||||||
`Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf1.Any", 1) + `,`,
|
`Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf1.Any", 1) + `,`,
|
||||||
`Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`,
|
`Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`,
|
||||||
`RootFS:` + fmt.Sprintf("%v", this.RootFS) + `,`,
|
`SnapshotKey:` + fmt.Sprintf("%v", this.SnapshotKey) + `,`,
|
||||||
`CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`,
|
`CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||||
`UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`,
|
`UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
|
@ -1426,7 +1428,7 @@ func (m *Container) Unmarshal(dAtA []byte) error {
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
case 7:
|
case 7:
|
||||||
if wireType != 2 {
|
if wireType != 2 {
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field RootFS", wireType)
|
return fmt.Errorf("proto: wrong wireType = %d for field SnapshotKey", wireType)
|
||||||
}
|
}
|
||||||
var stringLen uint64
|
var stringLen uint64
|
||||||
for shift := uint(0); ; shift += 7 {
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
@ -1451,7 +1453,7 @@ func (m *Container) Unmarshal(dAtA []byte) error {
|
||||||
if postIndex > l {
|
if postIndex > l {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
m.RootFS = string(dAtA[iNdEx:postIndex])
|
m.SnapshotKey = string(dAtA[iNdEx:postIndex])
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
case 8:
|
case 8:
|
||||||
if wireType != 2 {
|
if wireType != 2 {
|
||||||
|
@ -2507,52 +2509,51 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorContainers = []byte{
|
var fileDescriptorContainers = []byte{
|
||||||
// 738 bytes of a gzipped FileDescriptorProto
|
// 730 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x92, 0xd2, 0x40,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x72, 0x12, 0x41,
|
||||||
0x14, 0x9d, 0x40, 0x26, 0x0c, 0x97, 0x8d, 0xd5, 0x22, 0xc6, 0x58, 0x05, 0x98, 0x15, 0x0b, 0x0d,
|
0x14, 0xcd, 0xc0, 0x04, 0xc2, 0xc5, 0x85, 0xd5, 0x22, 0x8e, 0x63, 0x15, 0x10, 0x56, 0x2c, 0x74,
|
||||||
0x0e, 0x5a, 0x3a, 0x8f, 0xd5, 0x30, 0xaf, 0xb2, 0x6a, 0xc6, 0x9a, 0x6a, 0x75, 0xa3, 0x8b, 0x31,
|
0x30, 0x68, 0x69, 0x1e, 0xab, 0x90, 0x57, 0x59, 0x26, 0x56, 0xaa, 0x4b, 0x37, 0xba, 0x88, 0x0d,
|
||||||
0x40, 0xc3, 0x44, 0x92, 0x74, 0x4c, 0x37, 0x54, 0x51, 0x2e, 0xf4, 0x13, 0xfc, 0x0b, 0x7f, 0x65,
|
0x74, 0xc8, 0xc8, 0xbc, 0x9c, 0x6e, 0xa8, 0xa2, 0x5c, 0xe8, 0x27, 0xf8, 0x17, 0xfe, 0x4a, 0x96,
|
||||||
0x96, 0x2e, 0x5d, 0xcd, 0x83, 0x2f, 0xb1, 0xd2, 0x49, 0x26, 0xc8, 0xa3, 0x84, 0x51, 0x76, 0x7d,
|
0x2e, 0x5d, 0xc5, 0x84, 0x2f, 0xb1, 0xba, 0x67, 0x26, 0x43, 0x78, 0x94, 0x10, 0x65, 0x77, 0x2f,
|
||||||
0xe9, 0x7b, 0xee, 0x3d, 0x39, 0xf7, 0xdc, 0x10, 0x38, 0xea, 0x58, 0xfc, 0xac, 0xd7, 0x30, 0x9a,
|
0x7d, 0xcf, 0xbd, 0x67, 0x4e, 0x9f, 0x3b, 0x0c, 0x1c, 0xb6, 0x4d, 0x7e, 0xd6, 0x6d, 0x18, 0x4d,
|
||||||
0xd4, 0xa9, 0x36, 0xa9, 0xcb, 0x4d, 0xcb, 0x25, 0x7e, 0x6b, 0xf4, 0x68, 0x7a, 0x56, 0x95, 0x11,
|
0xd7, 0xae, 0x36, 0x5d, 0x87, 0x13, 0xd3, 0xa1, 0x7e, 0x6b, 0x38, 0x24, 0x9e, 0x59, 0x65, 0xd4,
|
||||||
0xbf, 0x6f, 0x35, 0x09, 0x4b, 0x7e, 0x67, 0xd5, 0xfe, 0xfa, 0x48, 0x64, 0x78, 0x3e, 0xe5, 0x14,
|
0xef, 0x99, 0x4d, 0xca, 0xe2, 0xdf, 0x59, 0xb5, 0xb7, 0x36, 0x94, 0x19, 0x9e, 0xef, 0x72, 0x17,
|
||||||
0x3d, 0x4a, 0x70, 0x46, 0x8c, 0x31, 0x46, 0xb2, 0xfa, 0xeb, 0x5a, 0xbe, 0x43, 0x3b, 0x54, 0x64,
|
0xad, 0xc6, 0x38, 0x23, 0xc2, 0x18, 0x43, 0x55, 0xbd, 0x35, 0x3d, 0xd7, 0x76, 0xdb, 0xae, 0xac,
|
||||||
0x57, 0x83, 0x53, 0x08, 0xd4, 0x1e, 0x74, 0x28, 0xed, 0xd8, 0xa4, 0x2a, 0xa2, 0x46, 0xaf, 0x5d,
|
0xae, 0x8a, 0x28, 0x00, 0xea, 0x0f, 0xdb, 0xae, 0xdb, 0xb6, 0x68, 0x55, 0x66, 0x8d, 0xee, 0x69,
|
||||||
0x35, 0xdd, 0x41, 0x74, 0xf5, 0x70, 0xfc, 0x8a, 0x38, 0x1e, 0x8f, 0x2f, 0xcb, 0xe3, 0x97, 0x6d,
|
0x95, 0x38, 0xfd, 0xf0, 0xe8, 0xd1, 0xe8, 0x11, 0xb5, 0x3d, 0x1e, 0x1d, 0x96, 0x46, 0x0f, 0x4f,
|
||||||
0x8b, 0xd8, 0xad, 0x53, 0xc7, 0x64, 0xdd, 0x28, 0xa3, 0x34, 0x9e, 0xc1, 0x2d, 0x87, 0x30, 0x6e,
|
0x4d, 0x6a, 0xb5, 0x4e, 0x6c, 0xc2, 0x3a, 0x61, 0x45, 0x71, 0xb4, 0x82, 0x9b, 0x36, 0x65, 0x9c,
|
||||||
0x3a, 0x5e, 0x98, 0xa0, 0x5f, 0xca, 0x90, 0xdd, 0x8d, 0x29, 0xa2, 0x02, 0xa4, 0xac, 0x96, 0x2a,
|
0xd8, 0x5e, 0x50, 0x50, 0xbe, 0x50, 0x21, 0xb3, 0x13, 0x51, 0x44, 0x79, 0x48, 0x98, 0x2d, 0x4d,
|
||||||
0x95, 0xa5, 0x4a, 0xb6, 0xae, 0x0c, 0x2f, 0x4a, 0xa9, 0x57, 0x7b, 0x38, 0x65, 0xb5, 0xd0, 0x09,
|
0x29, 0x29, 0x95, 0x4c, 0x3d, 0x35, 0xb8, 0x28, 0x26, 0x5e, 0xed, 0xe2, 0x84, 0xd9, 0x42, 0xc7,
|
||||||
0x28, 0xb6, 0xd9, 0x20, 0x36, 0x53, 0x53, 0xe5, 0x74, 0x25, 0x57, 0xdb, 0x30, 0xfe, 0xfa, 0xa8,
|
0x90, 0xb2, 0x48, 0x83, 0x5a, 0x4c, 0x4b, 0x94, 0x92, 0x95, 0x6c, 0x6d, 0xdd, 0xf8, 0xeb, 0xa3,
|
||||||
0xc6, 0x4d, 0x55, 0xe3, 0x48, 0x40, 0xf7, 0x5d, 0xee, 0x0f, 0x70, 0x54, 0x07, 0xe5, 0x61, 0xd5,
|
0x1a, 0xd7, 0x5d, 0x8d, 0x43, 0x09, 0xdd, 0x73, 0xb8, 0xdf, 0xc7, 0x61, 0x1f, 0x94, 0x83, 0x65,
|
||||||
0x72, 0xcc, 0x0e, 0x51, 0xd3, 0x41, 0x33, 0x1c, 0x06, 0xe8, 0x35, 0x64, 0xfc, 0x9e, 0x1b, 0x70,
|
0xd3, 0x26, 0x6d, 0xaa, 0x25, 0xc5, 0x30, 0x1c, 0x24, 0xe8, 0x0d, 0xa4, 0xfd, 0xae, 0x23, 0x38,
|
||||||
0x54, 0xe5, 0xb2, 0x54, 0xc9, 0xd5, 0x9e, 0x2f, 0xd4, 0x08, 0x87, 0x58, 0x1c, 0x17, 0x41, 0x15,
|
0x6a, 0x6a, 0x49, 0xa9, 0x64, 0x6b, 0xcf, 0xe7, 0x1a, 0x84, 0x03, 0x2c, 0x8e, 0x9a, 0xa0, 0x0a,
|
||||||
0x90, 0x99, 0x47, 0x9a, 0xea, 0xaa, 0x28, 0x96, 0x37, 0x42, 0x35, 0x8c, 0x58, 0x0d, 0x63, 0xc7,
|
0xa8, 0xcc, 0xa3, 0x4d, 0x6d, 0x59, 0x36, 0xcb, 0x19, 0x81, 0x1a, 0x46, 0xa4, 0x86, 0xb1, 0xed,
|
||||||
0x1d, 0x60, 0x91, 0x81, 0xca, 0x90, 0x63, 0xae, 0xe9, 0xb1, 0x33, 0xca, 0x39, 0xf1, 0x55, 0x45,
|
0xf4, 0xb1, 0xac, 0x40, 0x25, 0xc8, 0x32, 0x87, 0x78, 0xec, 0xcc, 0xe5, 0x9c, 0xfa, 0x5a, 0x4a,
|
||||||
0xb0, 0x1a, 0xfd, 0x09, 0xe9, 0xa0, 0xf8, 0x94, 0xf2, 0x36, 0x53, 0x33, 0x42, 0x1f, 0x18, 0x5e,
|
0xb2, 0x1a, 0xfe, 0x09, 0xad, 0xc2, 0x9d, 0x28, 0x3d, 0xe9, 0xd0, 0xbe, 0x96, 0xbe, 0x59, 0xf2,
|
||||||
0x94, 0x14, 0x4c, 0x29, 0x3f, 0x78, 0x83, 0xa3, 0x1b, 0xb4, 0x0b, 0xd0, 0xf4, 0x89, 0xc9, 0x49,
|
0x9a, 0xf6, 0xd1, 0x0e, 0x40, 0xd3, 0xa7, 0x84, 0xd3, 0xd6, 0x09, 0xe1, 0xda, 0x8a, 0x1c, 0xaa,
|
||||||
0xeb, 0xd4, 0xe4, 0xea, 0x9a, 0xe8, 0xaa, 0x4d, 0x74, 0x7d, 0x1b, 0xcf, 0xa0, 0xbe, 0x76, 0x7e,
|
0x8f, 0x0d, 0x7d, 0x1b, 0x5d, 0x41, 0x7d, 0xe5, 0xfc, 0xa2, 0xb8, 0xf4, 0xfd, 0x77, 0x51, 0xc1,
|
||||||
0x51, 0x5a, 0xf9, 0x7e, 0x59, 0x92, 0x70, 0x36, 0xc2, 0xed, 0xf0, 0xa0, 0x48, 0xcf, 0x6b, 0xc5,
|
0x99, 0x10, 0xb7, 0xcd, 0x45, 0x93, 0xae, 0xd7, 0x8a, 0x9a, 0x64, 0xe6, 0x69, 0x12, 0xe2, 0xb6,
|
||||||
0x45, 0xb2, 0x8b, 0x14, 0x89, 0x70, 0x3b, 0x5c, 0xdb, 0x84, 0xdc, 0x88, 0xec, 0xe8, 0x0e, 0xa4,
|
0xb9, 0xbe, 0x01, 0xd9, 0x21, 0xd5, 0xd1, 0x5d, 0x48, 0x0a, 0xca, 0xf2, 0x62, 0xb1, 0x08, 0x85,
|
||||||
0xbb, 0x64, 0x10, 0x4e, 0x16, 0x07, 0xc7, 0x60, 0x00, 0x7d, 0xd3, 0xee, 0x11, 0x35, 0x15, 0x0e,
|
0xfe, 0x3d, 0x62, 0x75, 0xa9, 0x96, 0x08, 0xf4, 0x97, 0xc9, 0x66, 0x62, 0x5d, 0xd1, 0x8f, 0x20,
|
||||||
0x40, 0x04, 0x5b, 0xa9, 0x0d, 0x49, 0x3b, 0x86, 0x4c, 0x24, 0x24, 0x42, 0x20, 0xbb, 0xa6, 0x43,
|
0x1d, 0xea, 0x88, 0x10, 0xa8, 0x0e, 0xb1, 0x69, 0x88, 0x93, 0x31, 0x32, 0x20, 0xed, 0x7a, 0xdc,
|
||||||
0x22, 0x9c, 0x38, 0x23, 0x03, 0x32, 0xd4, 0xe3, 0x16, 0x75, 0x99, 0x80, 0xce, 0x92, 0x35, 0x4e,
|
0x74, 0x1d, 0x26, 0xa1, 0xd3, 0x54, 0x8d, 0x8a, 0xca, 0x4f, 0xe0, 0xde, 0x01, 0xe5, 0xd7, 0x77,
|
||||||
0xd2, 0x9f, 0xc0, 0xdd, 0x43, 0xc2, 0x6f, 0x86, 0x84, 0xc9, 0xe7, 0x1e, 0x61, 0x7c, 0x96, 0xd5,
|
0x84, 0xe9, 0xe7, 0x2e, 0x65, 0x7c, 0x9a, 0xd3, 0xca, 0x67, 0x90, 0xbb, 0x59, 0xce, 0x3c, 0xd7,
|
||||||
0xf4, 0x33, 0xc8, 0xff, 0x99, 0xce, 0x3c, 0xea, 0x32, 0x82, 0x4e, 0x20, 0x7b, 0x33, 0x76, 0x01,
|
0x61, 0x14, 0x1d, 0x43, 0xe6, 0xfa, 0xd6, 0x25, 0x2c, 0x5b, 0x7b, 0x3c, 0x8f, 0x37, 0xea, 0xaa,
|
||||||
0xcb, 0xd5, 0x1e, 0x2f, 0x62, 0x8e, 0xba, 0x1c, 0xc8, 0x84, 0x93, 0x22, 0xfa, 0x3a, 0xdc, 0x3b,
|
0x90, 0x09, 0xc7, 0x4d, 0xca, 0x6b, 0x70, 0xff, 0xd0, 0x64, 0xf1, 0x28, 0x16, 0x51, 0xd3, 0x20,
|
||||||
0xb2, 0x58, 0xd2, 0x8a, 0xc5, 0xd4, 0x54, 0xc8, 0xb4, 0x2d, 0x9b, 0x13, 0x9f, 0xa9, 0x52, 0x39,
|
0x7d, 0x6a, 0x5a, 0x9c, 0xfa, 0x4c, 0x53, 0x4a, 0xc9, 0x4a, 0x06, 0x47, 0x69, 0xd9, 0x82, 0xfc,
|
||||||
0x5d, 0xc9, 0xe2, 0x38, 0xd4, 0x6d, 0x28, 0x8c, 0x43, 0x22, 0x7a, 0x18, 0x20, 0x69, 0x2c, 0x60,
|
0x28, 0x24, 0xa4, 0x87, 0x01, 0xe2, 0xc1, 0x12, 0x76, 0x3b, 0x7e, 0x43, 0x5d, 0xca, 0x9f, 0x20,
|
||||||
0xb7, 0xe3, 0x37, 0x52, 0x45, 0xff, 0x04, 0x85, 0x5d, 0xe1, 0x8a, 0x09, 0xf1, 0xfe, 0xbf, 0x18,
|
0xbf, 0x23, 0x5d, 0x31, 0x26, 0xde, 0xff, 0x17, 0xa3, 0x03, 0x0f, 0xc6, 0x66, 0x2d, 0x4c, 0xf9,
|
||||||
0x5d, 0xb8, 0x3f, 0xd1, 0x6b, 0x69, 0xca, 0xff, 0x90, 0xa0, 0xf0, 0x4e, 0x58, 0x75, 0xf9, 0x4f,
|
0x1f, 0x0a, 0xe4, 0xdf, 0x49, 0xab, 0x2e, 0xfe, 0xc9, 0xd0, 0x16, 0x64, 0x83, 0xb5, 0x90, 0xaf,
|
||||||
0x86, 0xb6, 0x21, 0x17, 0xae, 0x85, 0x78, 0x2f, 0x46, 0x9e, 0x9d, 0xdc, 0xa7, 0x83, 0xe0, 0xd5,
|
0xc5, 0xd0, 0xb3, 0xe3, 0xfb, 0xb4, 0x2f, 0xde, 0x9c, 0x47, 0x84, 0x75, 0x70, 0xb8, 0x7d, 0x22,
|
||||||
0x79, 0x6c, 0xb2, 0x2e, 0x8e, 0xb6, 0x2f, 0x38, 0x07, 0xb2, 0x4c, 0x10, 0x5d, 0x9a, 0x2c, 0x4f,
|
0x16, 0xb2, 0x8c, 0x11, 0x5d, 0x98, 0x2c, 0x4f, 0x21, 0xbf, 0x4b, 0x2d, 0x3a, 0x41, 0x95, 0x29,
|
||||||
0xa1, 0xb0, 0x47, 0x6c, 0x32, 0x45, 0x95, 0x19, 0xcb, 0x52, 0xbb, 0x92, 0x01, 0x12, 0x33, 0xa2,
|
0xcb, 0x52, 0xbb, 0x54, 0x01, 0x62, 0x33, 0xa2, 0x1e, 0x24, 0x0f, 0x28, 0x47, 0x2f, 0x66, 0xa0,
|
||||||
0x3e, 0xa4, 0x0f, 0x09, 0x47, 0x2f, 0xe6, 0xa0, 0x31, 0x65, 0x25, 0xb5, 0x97, 0x0b, 0xe3, 0x22,
|
0x31, 0x61, 0x25, 0xf5, 0x97, 0x73, 0xe3, 0x42, 0x29, 0xbe, 0x80, 0x2a, 0xd6, 0x02, 0xcd, 0xf2,
|
||||||
0x29, 0xbe, 0x80, 0x1c, 0xac, 0x05, 0x9a, 0xe7, 0x6f, 0x61, 0xea, 0xca, 0x69, 0x9b, 0xb7, 0x40,
|
0xaf, 0x30, 0x71, 0xe5, 0xf4, 0x8d, 0x5b, 0x20, 0xc3, 0xe1, 0x5f, 0x21, 0x15, 0x38, 0x17, 0xcd,
|
||||||
0x46, 0xcd, 0xbf, 0x82, 0x12, 0x3a, 0x17, 0xcd, 0x53, 0x64, 0xfa, 0x42, 0x69, 0x5b, 0xb7, 0x81,
|
0xd2, 0x64, 0xf2, 0x42, 0xe9, 0x9b, 0xb7, 0x81, 0xc6, 0x04, 0x02, 0x8f, 0xcc, 0x44, 0x60, 0xb2,
|
||||||
0x26, 0x04, 0x42, 0x8f, 0xcc, 0x45, 0x60, 0xba, 0xef, 0xe7, 0x22, 0x30, 0xcb, 0x89, 0x1f, 0x40,
|
0xef, 0x67, 0x22, 0x30, 0xcd, 0x89, 0x1f, 0x20, 0x15, 0xf8, 0x66, 0x26, 0x02, 0x93, 0x2d, 0xa6,
|
||||||
0x09, 0x7d, 0x33, 0x17, 0x81, 0xe9, 0x16, 0xd3, 0x0a, 0x13, 0x1b, 0xb1, 0x1f, 0x7c, 0x69, 0xd4,
|
0xe7, 0xc7, 0x36, 0x62, 0x4f, 0x7c, 0x68, 0xd4, 0x3f, 0x9e, 0x5f, 0x15, 0x96, 0x7e, 0x5d, 0x15,
|
||||||
0x3f, 0x9e, 0x5f, 0x17, 0x57, 0x7e, 0x5d, 0x17, 0x57, 0xbe, 0x0d, 0x8b, 0xd2, 0xf9, 0xb0, 0x28,
|
0x96, 0xbe, 0x0d, 0x0a, 0xca, 0xf9, 0xa0, 0xa0, 0xfc, 0x1c, 0x14, 0x94, 0xcb, 0x41, 0x41, 0x79,
|
||||||
0xfd, 0x1c, 0x16, 0xa5, 0xab, 0x61, 0x51, 0x7a, 0x7f, 0xf0, 0x0f, 0x1f, 0x4f, 0xdb, 0x49, 0xd4,
|
0xbf, 0xff, 0x0f, 0xdf, 0x4e, 0x5b, 0x71, 0xd6, 0x48, 0xc9, 0x89, 0xcf, 0xfe, 0x04, 0x00, 0x00,
|
||||||
0x50, 0x44, 0xc7, 0x67, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xef, 0xc2, 0x41, 0x7b, 0x8d, 0x09,
|
0xff, 0xff, 0x7e, 0x6d, 0xca, 0xbd, 0x8c, 0x09, 0x00, 0x00,
|
||||||
0x00, 0x00,
|
|
||||||
}
|
}
|
||||||
|
|
6
vendor/github.com/containerd/containerd/api/services/containers/v1/containers.proto
generated
vendored
6
vendor/github.com/containerd/containerd/api/services/containers/v1/containers.proto
generated
vendored
|
@ -67,15 +67,17 @@ message Container {
|
||||||
// Snapshotter specifies the snapshotter name used for rootfs
|
// Snapshotter specifies the snapshotter name used for rootfs
|
||||||
string snapshotter = 6;
|
string snapshotter = 6;
|
||||||
|
|
||||||
// RootFS specifies the snapshot key to use for the container's root
|
// SnapshotKey specifies the snapshot key to use for the container's root
|
||||||
// filesystem. When starting a task from this container, a caller should
|
// filesystem. When starting a task from this container, a caller should
|
||||||
// look up the mounts from the snapshot service and include those on the
|
// look up the mounts from the snapshot service and include those on the
|
||||||
// task create request.
|
// task create request.
|
||||||
//
|
//
|
||||||
// Snapshots referenced in this field will not be garbage collected.
|
// Snapshots referenced in this field will not be garbage collected.
|
||||||
//
|
//
|
||||||
|
// This field is set to empty when the rootfs is not a snapshot.
|
||||||
|
//
|
||||||
// This field may be updated.
|
// This field may be updated.
|
||||||
string rootfs = 7 [(gogoproto.customname) = "RootFS"];
|
string snapshot_key = 7;
|
||||||
|
|
||||||
// CreatedAt is the time the container was first created.
|
// CreatedAt is the time the container was first created.
|
||||||
google.protobuf.Timestamp created_at = 8 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
google.protobuf.Timestamp created_at = 8 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||||
|
|
76
vendor/github.com/containerd/containerd/api/services/events/v1/container.pb.go
generated
vendored
76
vendor/github.com/containerd/containerd/api/services/events/v1/container.pb.go
generated
vendored
|
@ -97,7 +97,7 @@ type ContainerUpdate struct {
|
||||||
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"`
|
Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"`
|
||||||
Labels map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Labels map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
RootFS string `protobuf:"bytes,4,opt,name=rootfs,proto3" json:"rootfs,omitempty"`
|
SnapshotKey string `protobuf:"bytes,4,opt,name=snapshot_key,json=snapshotKey,proto3" json:"snapshot_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ContainerUpdate) Reset() { *m = ContainerUpdate{} }
|
func (m *ContainerUpdate) Reset() { *m = ContainerUpdate{} }
|
||||||
|
@ -194,8 +194,8 @@ func (m *ContainerUpdate) Field(fieldpath []string) (string, bool) {
|
||||||
}
|
}
|
||||||
value, ok := m.Labels[strings.Join(fieldpath[1:], ".")]
|
value, ok := m.Labels[strings.Join(fieldpath[1:], ".")]
|
||||||
return value, ok
|
return value, ok
|
||||||
case "rootfs":
|
case "snapshot_key":
|
||||||
return string(m.RootFS), len(m.RootFS) > 0
|
return string(m.SnapshotKey), len(m.SnapshotKey) > 0
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
@ -331,11 +331,11 @@ func (m *ContainerUpdate) MarshalTo(dAtA []byte) (int, error) {
|
||||||
i += copy(dAtA[i:], v)
|
i += copy(dAtA[i:], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(m.RootFS) > 0 {
|
if len(m.SnapshotKey) > 0 {
|
||||||
dAtA[i] = 0x22
|
dAtA[i] = 0x22
|
||||||
i++
|
i++
|
||||||
i = encodeVarintContainer(dAtA, i, uint64(len(m.RootFS)))
|
i = encodeVarintContainer(dAtA, i, uint64(len(m.SnapshotKey)))
|
||||||
i += copy(dAtA[i:], m.RootFS)
|
i += copy(dAtA[i:], m.SnapshotKey)
|
||||||
}
|
}
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
@ -442,7 +442,7 @@ func (m *ContainerUpdate) Size() (n int) {
|
||||||
n += mapEntrySize + 1 + sovContainer(uint64(mapEntrySize))
|
n += mapEntrySize + 1 + sovContainer(uint64(mapEntrySize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l = len(m.RootFS)
|
l = len(m.SnapshotKey)
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
n += 1 + l + sovContainer(uint64(l))
|
n += 1 + l + sovContainer(uint64(l))
|
||||||
}
|
}
|
||||||
|
@ -513,7 +513,7 @@ func (this *ContainerUpdate) String() string {
|
||||||
`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
|
`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
|
||||||
`Image:` + fmt.Sprintf("%v", this.Image) + `,`,
|
`Image:` + fmt.Sprintf("%v", this.Image) + `,`,
|
||||||
`Labels:` + mapStringForLabels + `,`,
|
`Labels:` + mapStringForLabels + `,`,
|
||||||
`RootFS:` + fmt.Sprintf("%v", this.RootFS) + `,`,
|
`SnapshotKey:` + fmt.Sprintf("%v", this.SnapshotKey) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
}, "")
|
}, "")
|
||||||
return s
|
return s
|
||||||
|
@ -994,7 +994,7 @@ func (m *ContainerUpdate) Unmarshal(dAtA []byte) error {
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
case 4:
|
case 4:
|
||||||
if wireType != 2 {
|
if wireType != 2 {
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field RootFS", wireType)
|
return fmt.Errorf("proto: wrong wireType = %d for field SnapshotKey", wireType)
|
||||||
}
|
}
|
||||||
var stringLen uint64
|
var stringLen uint64
|
||||||
for shift := uint(0); ; shift += 7 {
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
@ -1019,7 +1019,7 @@ func (m *ContainerUpdate) Unmarshal(dAtA []byte) error {
|
||||||
if postIndex > l {
|
if postIndex > l {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
m.RootFS = string(dAtA[iNdEx:postIndex])
|
m.SnapshotKey = string(dAtA[iNdEx:postIndex])
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
default:
|
default:
|
||||||
iNdEx = preIndex
|
iNdEx = preIndex
|
||||||
|
@ -1231,32 +1231,32 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorContainer = []byte{
|
var fileDescriptorContainer = []byte{
|
||||||
// 429 bytes of a gzipped FileDescriptorProto
|
// 427 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x4d, 0x8b, 0xd4, 0x40,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x5d, 0x8b, 0xd4, 0x30,
|
||||||
0x10, 0xdd, 0xce, 0xac, 0x19, 0xec, 0x39, 0x28, 0xcd, 0x20, 0x71, 0xc0, 0xec, 0x30, 0xa7, 0xf1,
|
0x14, 0xdd, 0x74, 0xd6, 0x19, 0x4c, 0x05, 0x25, 0x0c, 0x52, 0x07, 0xac, 0xe3, 0x3c, 0x8d, 0x2f,
|
||||||
0xd2, 0xcd, 0x8e, 0x20, 0xba, 0x82, 0xe8, 0xee, 0xaa, 0x08, 0x0a, 0xd2, 0xe2, 0x45, 0xbc, 0xf4,
|
0x09, 0x3b, 0x82, 0xe8, 0x0a, 0xa2, 0xbb, 0x2b, 0x22, 0x2a, 0x48, 0xc0, 0x17, 0x11, 0x24, 0x9d,
|
||||||
0x4c, 0x6a, 0xb2, 0x8d, 0x49, 0x77, 0x48, 0x3a, 0x81, 0xdc, 0xfc, 0x29, 0xfe, 0x9c, 0x3d, 0x7a,
|
0xde, 0xed, 0x04, 0xdb, 0xa4, 0xb4, 0x69, 0xa1, 0x6f, 0xfe, 0x14, 0x7f, 0xce, 0x3e, 0xfa, 0xe8,
|
||||||
0xf4, 0xb4, 0xec, 0xe6, 0x27, 0x88, 0x3f, 0x40, 0xd2, 0x9d, 0xec, 0x06, 0xc1, 0xcf, 0xdb, 0xab,
|
0x93, 0xec, 0xf6, 0x1f, 0x08, 0xfe, 0x00, 0x69, 0x32, 0xdd, 0x2d, 0x82, 0x9f, 0x6f, 0xe7, 0xe6,
|
||||||
0xd4, 0x7b, 0x55, 0xef, 0x55, 0x1a, 0xbf, 0x88, 0xa5, 0x39, 0x29, 0xd7, 0x74, 0xa3, 0x53, 0xb6,
|
0x9e, 0x73, 0xef, 0x39, 0xb7, 0xc5, 0xcf, 0x12, 0x69, 0x36, 0x55, 0x44, 0xd7, 0x3a, 0x63, 0x6b,
|
||||||
0xd1, 0xca, 0x08, 0xa9, 0x20, 0x8f, 0x86, 0x50, 0x64, 0x92, 0x15, 0x90, 0x57, 0x72, 0x03, 0x05,
|
0xad, 0x8c, 0x90, 0x0a, 0x8a, 0x78, 0x08, 0x45, 0x2e, 0x59, 0x09, 0x45, 0x2d, 0xd7, 0x50, 0x32,
|
||||||
0x83, 0x0a, 0x94, 0x29, 0x58, 0xb5, 0x7f, 0xc5, 0xa0, 0x59, 0xae, 0x8d, 0x26, 0x77, 0xae, 0x24,
|
0xa8, 0x41, 0x99, 0x92, 0xd5, 0x7b, 0x17, 0x0c, 0x9a, 0x17, 0xda, 0x68, 0x72, 0xf3, 0x42, 0x42,
|
||||||
0xb4, 0xa7, 0x53, 0x47, 0xa7, 0xd5, 0xfe, 0x6c, 0x1a, 0xeb, 0x58, 0x5b, 0x26, 0x6b, 0x91, 0x13,
|
0x7b, 0x3a, 0x75, 0x74, 0x5a, 0xef, 0xcd, 0xa6, 0x89, 0x4e, 0xb4, 0x65, 0xb2, 0x0e, 0x39, 0xd1,
|
||||||
0xcd, 0x6e, 0xc7, 0x5a, 0xc7, 0x09, 0x30, 0x5b, 0xad, 0xcb, 0x2d, 0x13, 0xaa, 0xee, 0x5a, 0x4f,
|
0xec, 0x46, 0xa2, 0x75, 0x92, 0x02, 0xb3, 0x55, 0x54, 0x1d, 0x33, 0xa1, 0x9a, 0x6d, 0xeb, 0xf1,
|
||||||
0xfe, 0x68, 0xec, 0x52, 0x94, 0x25, 0x65, 0x2c, 0x15, 0xdb, 0x4a, 0x48, 0xa2, 0x4c, 0x98, 0x13,
|
0x1f, 0x8d, 0x9d, 0x8b, 0xf2, 0xb4, 0x4a, 0xa4, 0x62, 0xc7, 0x12, 0xd2, 0x38, 0x17, 0x66, 0xe3,
|
||||||
0x37, 0x61, 0x71, 0x8e, 0xf0, 0x8d, 0xa3, 0x9e, 0x7e, 0x94, 0x83, 0x30, 0x40, 0x6e, 0x61, 0x4f,
|
0x26, 0x2c, 0x4e, 0x11, 0xbe, 0x7a, 0xd8, 0xd3, 0x0f, 0x0b, 0x10, 0x06, 0xc8, 0x75, 0xec, 0xc9,
|
||||||
0x46, 0x01, 0x9a, 0xa3, 0xe5, 0xf5, 0x43, 0xbf, 0x39, 0xdb, 0xf3, 0x5e, 0x1e, 0x73, 0x4f, 0x46,
|
0x38, 0x40, 0x73, 0xb4, 0xbc, 0x7c, 0x30, 0x6e, 0xbf, 0xde, 0xf2, 0x9e, 0x1f, 0x71, 0x4f, 0xc6,
|
||||||
0x64, 0x8a, 0xaf, 0xc9, 0x54, 0xc4, 0x10, 0x78, 0x6d, 0x8b, 0xbb, 0x82, 0xbc, 0xc1, 0xe3, 0xbc,
|
0x64, 0x8a, 0x2f, 0xc9, 0x4c, 0x24, 0x10, 0x78, 0x5d, 0x8b, 0xbb, 0x82, 0xbc, 0xc6, 0x93, 0xa2,
|
||||||
0x54, 0x46, 0xa6, 0x10, 0x8c, 0xe6, 0x68, 0x39, 0x59, 0xdd, 0xa7, 0xbf, 0x4d, 0x49, 0x7f, 0x5a,
|
0x52, 0x46, 0x66, 0x10, 0x8c, 0xe6, 0x68, 0xe9, 0xaf, 0xee, 0xd1, 0xdf, 0xa6, 0xa4, 0x3f, 0xad,
|
||||||
0x47, 0xb9, 0x53, 0xf3, 0x7e, 0xcc, 0xec, 0x35, 0x1e, 0x77, 0xdf, 0x08, 0xc1, 0xbb, 0x4a, 0xa4,
|
0xa3, 0xdc, 0xa9, 0x79, 0x3f, 0x66, 0xf6, 0x0a, 0x4f, 0xb6, 0x6f, 0x84, 0xe0, 0x5d, 0x25, 0x32,
|
||||||
0xe0, 0xcc, 0x70, 0x8b, 0x09, 0xc5, 0x63, 0x9d, 0x19, 0xa9, 0x55, 0x61, 0x8d, 0x4c, 0x56, 0x53,
|
0x70, 0x66, 0xb8, 0xc5, 0x84, 0xe2, 0x89, 0xce, 0x8d, 0xd4, 0xaa, 0xb4, 0x46, 0xfc, 0xd5, 0x94,
|
||||||
0xea, 0x2e, 0x44, 0xfb, 0xb0, 0xf4, 0xa9, 0xaa, 0x79, 0x4f, 0x5a, 0x7c, 0x1b, 0x46, 0x7c, 0x97,
|
0xba, 0x0b, 0xd1, 0x3e, 0x2c, 0x7d, 0xa2, 0x1a, 0xde, 0x93, 0x16, 0xdf, 0x86, 0x11, 0xdf, 0xe4,
|
||||||
0x45, 0xff, 0x1e, 0x91, 0x63, 0x3f, 0x11, 0x6b, 0x48, 0x8a, 0x60, 0x34, 0x1f, 0x2d, 0x27, 0xab,
|
0xf1, 0xbf, 0x47, 0xe4, 0x78, 0x9c, 0x8a, 0x08, 0xd2, 0x32, 0x18, 0xcd, 0x47, 0x4b, 0x7f, 0xb5,
|
||||||
0x83, 0xbf, 0x4d, 0xe8, 0xb6, 0xd1, 0x57, 0x56, 0xfc, 0x4c, 0x99, 0xbc, 0xe6, 0xdd, 0x24, 0xb2,
|
0xff, 0xb7, 0x09, 0xdd, 0x36, 0xfa, 0xd2, 0x8a, 0x9f, 0x2a, 0x53, 0x34, 0x7c, 0x3b, 0x89, 0xdc,
|
||||||
0xc0, 0x7e, 0xae, 0xb5, 0xd9, 0x16, 0xc1, 0xae, 0x75, 0x81, 0x9b, 0xb3, 0x3d, 0x9f, 0x6b, 0x6d,
|
0xc6, 0x57, 0x4a, 0x25, 0xf2, 0x72, 0xa3, 0xcd, 0xfb, 0x0f, 0xd0, 0x04, 0xbb, 0x76, 0xa1, 0xdf,
|
||||||
0x9e, 0xbf, 0xe5, 0x5d, 0x67, 0xf6, 0x10, 0x4f, 0x06, 0x52, 0x72, 0x13, 0x8f, 0x3e, 0x42, 0xdd,
|
0xbf, 0xbd, 0x80, 0x66, 0xf6, 0x00, 0xfb, 0x03, 0x25, 0xb9, 0x86, 0x47, 0x1d, 0xd1, 0x9d, 0xa2,
|
||||||
0xdd, 0xa2, 0x85, 0xad, 0xdd, 0x4a, 0x24, 0xe5, 0xa5, 0x5d, 0x5b, 0x1c, 0x78, 0x0f, 0xd0, 0xe2,
|
0x83, 0x9d, 0xdb, 0x5a, 0xa4, 0xd5, 0xb9, 0x5b, 0x5b, 0xec, 0x7b, 0xf7, 0xd1, 0xe2, 0xce, 0x20,
|
||||||
0xee, 0x20, 0xf3, 0x31, 0x24, 0xf0, 0xeb, 0xcc, 0x87, 0x1f, 0x4e, 0x2f, 0xc2, 0x9d, 0xaf, 0x17,
|
0xf2, 0x11, 0xa4, 0xf0, 0xeb, 0xc8, 0x07, 0xef, 0x4e, 0xce, 0xc2, 0x9d, 0x2f, 0x67, 0xe1, 0xce,
|
||||||
0xe1, 0xce, 0xa7, 0x26, 0x44, 0xa7, 0x4d, 0x88, 0xbe, 0x34, 0x21, 0x3a, 0x6f, 0x42, 0xf4, 0xf9,
|
0xc7, 0x36, 0x44, 0x27, 0x6d, 0x88, 0x3e, 0xb7, 0x21, 0x3a, 0x6d, 0x43, 0xf4, 0xe9, 0x7b, 0x88,
|
||||||
0x7b, 0x88, 0xde, 0x3f, 0xfe, 0xcf, 0xb7, 0xff, 0xc8, 0xa1, 0xb5, 0x6f, 0x7f, 0xca, 0xbd, 0x1f,
|
0xde, 0x3e, 0xfa, 0xcf, 0x5f, 0xff, 0xa1, 0x43, 0xd1, 0xd8, 0x7e, 0x93, 0xbb, 0x3f, 0x02, 0x00,
|
||||||
0x01, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xae, 0x41, 0x3c, 0x44, 0x03, 0x00, 0x00,
|
0x00, 0xff, 0xff, 0x26, 0x0d, 0x55, 0x1c, 0x43, 0x03, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ message ContainerUpdate {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string image = 2;
|
string image = 2;
|
||||||
map<string, string> labels = 3;
|
map<string, string> labels = 3;
|
||||||
string rootfs = 4 [(gogoproto.customname) = "RootFS"];
|
string snapshot_key = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ContainerDelete {
|
message ContainerDelete {
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
CheckpointTaskRequest
|
CheckpointTaskRequest
|
||||||
CheckpointTaskResponse
|
CheckpointTaskResponse
|
||||||
UpdateTaskRequest
|
UpdateTaskRequest
|
||||||
|
MetricsRequest
|
||||||
|
MetricsResponse
|
||||||
*/
|
*/
|
||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
|
@ -43,6 +45,7 @@ import google_protobuf1 "github.com/gogo/protobuf/types"
|
||||||
import _ "github.com/gogo/protobuf/gogoproto"
|
import _ "github.com/gogo/protobuf/gogoproto"
|
||||||
import containerd_types "github.com/containerd/containerd/api/types"
|
import containerd_types "github.com/containerd/containerd/api/types"
|
||||||
import containerd_types1 "github.com/containerd/containerd/api/types"
|
import containerd_types1 "github.com/containerd/containerd/api/types"
|
||||||
|
import containerd_types2 "github.com/containerd/containerd/api/types"
|
||||||
import containerd_v1_types "github.com/containerd/containerd/api/types/task"
|
import containerd_v1_types "github.com/containerd/containerd/api/types/task"
|
||||||
import _ "github.com/gogo/protobuf/types"
|
import _ "github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
|
@ -86,7 +89,7 @@ type CreateTaskRequest struct {
|
||||||
Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"`
|
Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"`
|
||||||
Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"`
|
Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"`
|
||||||
Terminal bool `protobuf:"varint,7,opt,name=terminal,proto3" json:"terminal,omitempty"`
|
Terminal bool `protobuf:"varint,7,opt,name=terminal,proto3" json:"terminal,omitempty"`
|
||||||
Checkpoint *containerd_types1.Descriptor `protobuf:"bytes,8,opt,name=checkpoint" json:"checkpoint,omitempty"`
|
Checkpoint *containerd_types2.Descriptor `protobuf:"bytes,8,opt,name=checkpoint" json:"checkpoint,omitempty"`
|
||||||
Options *google_protobuf1.Any `protobuf:"bytes,9,opt,name=options" json:"options,omitempty"`
|
Options *google_protobuf1.Any `protobuf:"bytes,9,opt,name=options" json:"options,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +284,7 @@ func (*CheckpointTaskRequest) ProtoMessage() {}
|
||||||
func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{20} }
|
func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{20} }
|
||||||
|
|
||||||
type CheckpointTaskResponse struct {
|
type CheckpointTaskResponse struct {
|
||||||
Descriptors []*containerd_types1.Descriptor `protobuf:"bytes,1,rep,name=descriptors" json:"descriptors,omitempty"`
|
Descriptors []*containerd_types2.Descriptor `protobuf:"bytes,1,rep,name=descriptors" json:"descriptors,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CheckpointTaskResponse) Reset() { *m = CheckpointTaskResponse{} }
|
func (m *CheckpointTaskResponse) Reset() { *m = CheckpointTaskResponse{} }
|
||||||
|
@ -297,6 +300,22 @@ func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{
|
||||||
func (*UpdateTaskRequest) ProtoMessage() {}
|
func (*UpdateTaskRequest) ProtoMessage() {}
|
||||||
func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{22} }
|
func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{22} }
|
||||||
|
|
||||||
|
type MetricsRequest struct {
|
||||||
|
Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsRequest) Reset() { *m = MetricsRequest{} }
|
||||||
|
func (*MetricsRequest) ProtoMessage() {}
|
||||||
|
func (*MetricsRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{23} }
|
||||||
|
|
||||||
|
type MetricsResponse struct {
|
||||||
|
Metrics []*containerd_types1.Metric `protobuf:"bytes,1,rep,name=metrics" json:"metrics,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsResponse) Reset() { *m = MetricsResponse{} }
|
||||||
|
func (*MetricsResponse) ProtoMessage() {}
|
||||||
|
func (*MetricsResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{24} }
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterType((*CreateTaskRequest)(nil), "containerd.services.tasks.v1.CreateTaskRequest")
|
proto.RegisterType((*CreateTaskRequest)(nil), "containerd.services.tasks.v1.CreateTaskRequest")
|
||||||
proto.RegisterType((*CreateTaskResponse)(nil), "containerd.services.tasks.v1.CreateTaskResponse")
|
proto.RegisterType((*CreateTaskResponse)(nil), "containerd.services.tasks.v1.CreateTaskResponse")
|
||||||
|
@ -321,6 +340,8 @@ func init() {
|
||||||
proto.RegisterType((*CheckpointTaskRequest)(nil), "containerd.services.tasks.v1.CheckpointTaskRequest")
|
proto.RegisterType((*CheckpointTaskRequest)(nil), "containerd.services.tasks.v1.CheckpointTaskRequest")
|
||||||
proto.RegisterType((*CheckpointTaskResponse)(nil), "containerd.services.tasks.v1.CheckpointTaskResponse")
|
proto.RegisterType((*CheckpointTaskResponse)(nil), "containerd.services.tasks.v1.CheckpointTaskResponse")
|
||||||
proto.RegisterType((*UpdateTaskRequest)(nil), "containerd.services.tasks.v1.UpdateTaskRequest")
|
proto.RegisterType((*UpdateTaskRequest)(nil), "containerd.services.tasks.v1.UpdateTaskRequest")
|
||||||
|
proto.RegisterType((*MetricsRequest)(nil), "containerd.services.tasks.v1.MetricsRequest")
|
||||||
|
proto.RegisterType((*MetricsResponse)(nil), "containerd.services.tasks.v1.MetricsResponse")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
@ -353,6 +374,7 @@ type TasksClient interface {
|
||||||
ListPids(ctx context.Context, in *ListPidsRequest, opts ...grpc.CallOption) (*ListPidsResponse, error)
|
ListPids(ctx context.Context, in *ListPidsRequest, opts ...grpc.CallOption) (*ListPidsResponse, error)
|
||||||
Checkpoint(ctx context.Context, in *CheckpointTaskRequest, opts ...grpc.CallOption) (*CheckpointTaskResponse, error)
|
Checkpoint(ctx context.Context, in *CheckpointTaskRequest, opts ...grpc.CallOption) (*CheckpointTaskResponse, error)
|
||||||
Update(ctx context.Context, in *UpdateTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error)
|
Update(ctx context.Context, in *UpdateTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error)
|
||||||
|
Metrics(ctx context.Context, in *MetricsRequest, opts ...grpc.CallOption) (*MetricsResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type tasksClient struct {
|
type tasksClient struct {
|
||||||
|
@ -498,6 +520,15 @@ func (c *tasksClient) Update(ctx context.Context, in *UpdateTaskRequest, opts ..
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *tasksClient) Metrics(ctx context.Context, in *MetricsRequest, opts ...grpc.CallOption) (*MetricsResponse, error) {
|
||||||
|
out := new(MetricsResponse)
|
||||||
|
err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Metrics", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Server API for Tasks service
|
// Server API for Tasks service
|
||||||
|
|
||||||
type TasksServer interface {
|
type TasksServer interface {
|
||||||
|
@ -520,6 +551,7 @@ type TasksServer interface {
|
||||||
ListPids(context.Context, *ListPidsRequest) (*ListPidsResponse, error)
|
ListPids(context.Context, *ListPidsRequest) (*ListPidsResponse, error)
|
||||||
Checkpoint(context.Context, *CheckpointTaskRequest) (*CheckpointTaskResponse, error)
|
Checkpoint(context.Context, *CheckpointTaskRequest) (*CheckpointTaskResponse, error)
|
||||||
Update(context.Context, *UpdateTaskRequest) (*google_protobuf.Empty, error)
|
Update(context.Context, *UpdateTaskRequest) (*google_protobuf.Empty, error)
|
||||||
|
Metrics(context.Context, *MetricsRequest) (*MetricsResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterTasksServer(s *grpc.Server, srv TasksServer) {
|
func RegisterTasksServer(s *grpc.Server, srv TasksServer) {
|
||||||
|
@ -796,6 +828,24 @@ func _Tasks_Update_Handler(srv interface{}, ctx context.Context, dec func(interf
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _Tasks_Metrics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(MetricsRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(TasksServer).Metrics(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/containerd.services.tasks.v1.Tasks/Metrics",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(TasksServer).Metrics(ctx, req.(*MetricsRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
var _Tasks_serviceDesc = grpc.ServiceDesc{
|
var _Tasks_serviceDesc = grpc.ServiceDesc{
|
||||||
ServiceName: "containerd.services.tasks.v1.Tasks",
|
ServiceName: "containerd.services.tasks.v1.Tasks",
|
||||||
HandlerType: (*TasksServer)(nil),
|
HandlerType: (*TasksServer)(nil),
|
||||||
|
@ -860,6 +910,10 @@ var _Tasks_serviceDesc = grpc.ServiceDesc{
|
||||||
MethodName: "Update",
|
MethodName: "Update",
|
||||||
Handler: _Tasks_Update_Handler,
|
Handler: _Tasks_Update_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Metrics",
|
||||||
|
Handler: _Tasks_Metrics_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "github.com/containerd/containerd/api/services/tasks/v1/tasks.proto",
|
Metadata: "github.com/containerd/containerd/api/services/tasks/v1/tasks.proto",
|
||||||
|
@ -1661,6 +1715,69 @@ func (m *UpdateTaskRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MetricsRequest) 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 *MetricsRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
var i int
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Filters) > 0 {
|
||||||
|
for _, s := range m.Filters {
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
i++
|
||||||
|
l = len(s)
|
||||||
|
for l >= 1<<7 {
|
||||||
|
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
|
||||||
|
l >>= 7
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
dAtA[i] = uint8(l)
|
||||||
|
i++
|
||||||
|
i += copy(dAtA[i:], s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsResponse) 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 *MetricsResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
var i int
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Metrics) > 0 {
|
||||||
|
for _, msg := range m.Metrics {
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
i++
|
||||||
|
i = encodeVarintTasks(dAtA, i, uint64(msg.Size()))
|
||||||
|
n, err := msg.MarshalTo(dAtA[i:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i += n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
func encodeFixed64Tasks(dAtA []byte, offset int, v uint64) int {
|
func encodeFixed64Tasks(dAtA []byte, offset int, v uint64) int {
|
||||||
dAtA[offset] = uint8(v)
|
dAtA[offset] = uint8(v)
|
||||||
dAtA[offset+1] = uint8(v >> 8)
|
dAtA[offset+1] = uint8(v >> 8)
|
||||||
|
@ -2034,6 +2151,30 @@ func (m *UpdateTaskRequest) Size() (n int) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MetricsRequest) Size() (n int) {
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Filters) > 0 {
|
||||||
|
for _, s := range m.Filters {
|
||||||
|
l = len(s)
|
||||||
|
n += 1 + l + sovTasks(uint64(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MetricsResponse) Size() (n int) {
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Metrics) > 0 {
|
||||||
|
for _, e := range m.Metrics {
|
||||||
|
l = e.Size()
|
||||||
|
n += 1 + l + sovTasks(uint64(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
func sovTasks(x uint64) (n int) {
|
func sovTasks(x uint64) (n int) {
|
||||||
for {
|
for {
|
||||||
n++
|
n++
|
||||||
|
@ -2058,7 +2199,7 @@ func (this *CreateTaskRequest) String() string {
|
||||||
`Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`,
|
`Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`,
|
||||||
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
|
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
|
||||||
`Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`,
|
`Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`,
|
||||||
`Checkpoint:` + strings.Replace(fmt.Sprintf("%v", this.Checkpoint), "Descriptor", "containerd_types1.Descriptor", 1) + `,`,
|
`Checkpoint:` + strings.Replace(fmt.Sprintf("%v", this.Checkpoint), "Descriptor", "containerd_types2.Descriptor", 1) + `,`,
|
||||||
`Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf1.Any", 1) + `,`,
|
`Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf1.Any", 1) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
}, "")
|
}, "")
|
||||||
|
@ -2291,7 +2432,7 @@ func (this *CheckpointTaskResponse) String() string {
|
||||||
return "nil"
|
return "nil"
|
||||||
}
|
}
|
||||||
s := strings.Join([]string{`&CheckpointTaskResponse{`,
|
s := strings.Join([]string{`&CheckpointTaskResponse{`,
|
||||||
`Descriptors:` + strings.Replace(fmt.Sprintf("%v", this.Descriptors), "Descriptor", "containerd_types1.Descriptor", 1) + `,`,
|
`Descriptors:` + strings.Replace(fmt.Sprintf("%v", this.Descriptors), "Descriptor", "containerd_types2.Descriptor", 1) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
}, "")
|
}, "")
|
||||||
return s
|
return s
|
||||||
|
@ -2307,6 +2448,26 @@ func (this *UpdateTaskRequest) String() string {
|
||||||
}, "")
|
}, "")
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
func (this *MetricsRequest) String() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
s := strings.Join([]string{`&MetricsRequest{`,
|
||||||
|
`Filters:` + fmt.Sprintf("%v", this.Filters) + `,`,
|
||||||
|
`}`,
|
||||||
|
}, "")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
func (this *MetricsResponse) String() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
s := strings.Join([]string{`&MetricsResponse{`,
|
||||||
|
`Metrics:` + strings.Replace(fmt.Sprintf("%v", this.Metrics), "Metric", "containerd_types1.Metric", 1) + `,`,
|
||||||
|
`}`,
|
||||||
|
}, "")
|
||||||
|
return s
|
||||||
|
}
|
||||||
func valueToStringTasks(v interface{}) string {
|
func valueToStringTasks(v interface{}) string {
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.IsNil() {
|
if rv.IsNil() {
|
||||||
|
@ -2538,7 +2699,7 @@ func (m *CreateTaskRequest) Unmarshal(dAtA []byte) error {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
if m.Checkpoint == nil {
|
if m.Checkpoint == nil {
|
||||||
m.Checkpoint = &containerd_types1.Descriptor{}
|
m.Checkpoint = &containerd_types2.Descriptor{}
|
||||||
}
|
}
|
||||||
if err := m.Checkpoint.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
if err := m.Checkpoint.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -4822,7 +4983,7 @@ func (m *CheckpointTaskResponse) Unmarshal(dAtA []byte) error {
|
||||||
if postIndex > l {
|
if postIndex > l {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
m.Descriptors = append(m.Descriptors, &containerd_types1.Descriptor{})
|
m.Descriptors = append(m.Descriptors, &containerd_types2.Descriptor{})
|
||||||
if err := m.Descriptors[len(m.Descriptors)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
if err := m.Descriptors[len(m.Descriptors)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4960,6 +5121,166 @@ func (m *UpdateTaskRequest) Unmarshal(dAtA []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (m *MetricsRequest) 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 ErrIntOverflowTasks
|
||||||
|
}
|
||||||
|
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: MetricsRequest: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: MetricsRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowTasks
|
||||||
|
}
|
||||||
|
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 ErrInvalidLengthTasks
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex]))
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipTasks(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthTasks
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *MetricsResponse) 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 ErrIntOverflowTasks
|
||||||
|
}
|
||||||
|
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: MetricsResponse: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: MetricsResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Metrics", wireType)
|
||||||
|
}
|
||||||
|
var msglen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowTasks
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
msglen |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if msglen < 0 {
|
||||||
|
return ErrInvalidLengthTasks
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + msglen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Metrics = append(m.Metrics, &containerd_types1.Metric{})
|
||||||
|
if err := m.Metrics[len(m.Metrics)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipTasks(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthTasks
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
func skipTasks(dAtA []byte) (n int, err error) {
|
func skipTasks(dAtA []byte) (n int, err error) {
|
||||||
l := len(dAtA)
|
l := len(dAtA)
|
||||||
iNdEx := 0
|
iNdEx := 0
|
||||||
|
@ -5070,81 +5391,85 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorTasks = []byte{
|
var fileDescriptorTasks = []byte{
|
||||||
// 1207 bytes of a gzipped FileDescriptorProto
|
// 1274 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0x1b, 0x45,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4f, 0x6f, 0x1b, 0x45,
|
||||||
0x14, 0xef, 0xfa, 0x63, 0x6d, 0x3f, 0x37, 0x6d, 0x32, 0xa4, 0xc1, 0x2c, 0x95, 0x1d, 0x16, 0x09,
|
0x14, 0xef, 0xc6, 0xf6, 0xda, 0x7e, 0x6e, 0xda, 0x64, 0x48, 0xc3, 0xb2, 0x54, 0x71, 0x58, 0x24,
|
||||||
0x99, 0x42, 0x77, 0xa9, 0x8b, 0x7a, 0xa0, 0x15, 0x52, 0x13, 0x87, 0xc8, 0x02, 0xd4, 0x74, 0x53,
|
0x64, 0x02, 0xdd, 0xa5, 0x2e, 0xaa, 0x10, 0xad, 0x90, 0x9a, 0x3f, 0x44, 0x16, 0x54, 0x4d, 0xb7,
|
||||||
0x10, 0xca, 0xc5, 0x6c, 0xbc, 0x13, 0x67, 0x14, 0x7b, 0x77, 0xbb, 0x33, 0x4e, 0x13, 0x38, 0xc0,
|
0x05, 0xa1, 0x5e, 0xc2, 0x76, 0x77, 0xe2, 0x8c, 0x62, 0xef, 0x6e, 0x77, 0xc6, 0x69, 0x03, 0x07,
|
||||||
0x9f, 0xd0, 0x0b, 0x07, 0x2e, 0xfc, 0x3d, 0x39, 0x72, 0x44, 0x08, 0x05, 0xea, 0xff, 0x82, 0x1b,
|
0xf8, 0x08, 0xbd, 0x72, 0xe1, 0xf3, 0xe4, 0xc8, 0x11, 0x21, 0x14, 0xa8, 0xbf, 0x05, 0x07, 0x24,
|
||||||
0x9a, 0x0f, 0x6f, 0x36, 0x76, 0xfc, 0x91, 0xba, 0xe1, 0x92, 0xcc, 0xcc, 0xbe, 0xaf, 0xf9, 0xbd,
|
0x34, 0x7f, 0x76, 0xb3, 0xb1, 0xe3, 0xd8, 0xa9, 0x1b, 0x2e, 0xed, 0xcc, 0xec, 0xef, 0xbd, 0x79,
|
||||||
0x37, 0xbf, 0xf7, 0x12, 0x58, 0x6b, 0x13, 0xb6, 0xdf, 0xdb, 0xb5, 0x5a, 0x41, 0xd7, 0x6e, 0x05,
|
0xf3, 0x9b, 0x37, 0xef, 0xfd, 0x1c, 0x58, 0x6d, 0x13, 0xb6, 0xdb, 0x7b, 0x6a, 0xfb, 0x51, 0xd7,
|
||||||
0x3e, 0x73, 0x89, 0x8f, 0x23, 0x2f, 0xb9, 0x74, 0x43, 0x62, 0x53, 0x1c, 0x1d, 0x92, 0x16, 0xa6,
|
0xf1, 0xa3, 0x90, 0x79, 0x24, 0xc4, 0x49, 0x90, 0x1f, 0x7a, 0x31, 0x71, 0x28, 0x4e, 0xf6, 0x89,
|
||||||
0x36, 0x73, 0xe9, 0x01, 0xb5, 0x0f, 0xef, 0xc9, 0x85, 0x15, 0x46, 0x01, 0x0b, 0xd0, 0xed, 0x33,
|
0x8f, 0xa9, 0xc3, 0x3c, 0xba, 0x47, 0x9d, 0xfd, 0x9b, 0x72, 0x60, 0xc7, 0x49, 0xc4, 0x22, 0x74,
|
||||||
0x69, 0x6b, 0x20, 0x69, 0x49, 0x81, 0xc3, 0x7b, 0xc6, 0xbb, 0xed, 0x20, 0x68, 0x77, 0xb0, 0x2d,
|
0xfd, 0x18, 0x6d, 0xa7, 0x48, 0x5b, 0x02, 0xf6, 0x6f, 0x9a, 0xef, 0xb6, 0xa3, 0xa8, 0xdd, 0xc1,
|
||||||
0x64, 0x77, 0x7b, 0x7b, 0x36, 0xee, 0x86, 0xec, 0x58, 0xaa, 0x1a, 0xef, 0x0c, 0x7f, 0x74, 0xfd,
|
0x8e, 0xc0, 0x3e, 0xed, 0xed, 0x38, 0xb8, 0x1b, 0xb3, 0x03, 0x69, 0x6a, 0xbe, 0x33, 0xf8, 0xd1,
|
||||||
0xc1, 0xa7, 0xe5, 0x76, 0xd0, 0x0e, 0xc4, 0xd2, 0xe6, 0x2b, 0x75, 0xfa, 0x60, 0xa6, 0x78, 0xd9,
|
0x0b, 0xd3, 0x4f, 0x0b, 0xed, 0xa8, 0x1d, 0x89, 0xa1, 0xc3, 0x47, 0x6a, 0xf5, 0xf6, 0x44, 0xf1,
|
||||||
0x71, 0x88, 0xa9, 0xdd, 0x0d, 0x7a, 0x3e, 0x53, 0x7a, 0x0f, 0x2f, 0xa1, 0xe7, 0x61, 0xda, 0x8a,
|
0xb2, 0x83, 0x18, 0x53, 0xa7, 0x1b, 0xf5, 0x42, 0xa6, 0xec, 0x3e, 0x3b, 0x8f, 0x1d, 0x66, 0x09,
|
||||||
0x48, 0xc8, 0x82, 0x48, 0x29, 0x7f, 0x76, 0x09, 0x65, 0x7e, 0x6f, 0xf1, 0x43, 0xe9, 0x56, 0x86,
|
0xf1, 0xd5, 0xe9, 0xcc, 0x3b, 0xe7, 0xb0, 0x0c, 0x30, 0xf5, 0x13, 0x12, 0xb3, 0x28, 0x51, 0xc6,
|
||||||
0x6f, 0xc8, 0x48, 0x17, 0x53, 0xe6, 0x76, 0x43, 0x29, 0x60, 0x9e, 0xa4, 0x60, 0x69, 0x3d, 0xc2,
|
0x9f, 0x9f, 0xc3, 0x98, 0x33, 0x26, 0xfe, 0x51, 0xb6, 0xf5, 0x41, 0x6e, 0x18, 0xe9, 0x62, 0xca,
|
||||||
0x2e, 0xc3, 0xcf, 0x5c, 0x7a, 0xe0, 0xe0, 0xe7, 0x3d, 0x4c, 0x19, 0xaa, 0xc1, 0xf5, 0xd8, 0x7c,
|
0xbc, 0x6e, 0x2c, 0x01, 0xd6, 0xe1, 0x0c, 0xcc, 0xaf, 0x25, 0xd8, 0x63, 0xf8, 0xb1, 0x47, 0xf7,
|
||||||
0x93, 0x78, 0x25, 0x6d, 0x55, 0xab, 0x16, 0xd6, 0x6e, 0xf6, 0x4f, 0x2b, 0xc5, 0xf5, 0xc1, 0x79,
|
0x5c, 0xfc, 0xac, 0x87, 0x29, 0x43, 0x4d, 0xb8, 0x9c, 0xb9, 0xdf, 0x26, 0x81, 0xa1, 0x2d, 0x6b,
|
||||||
0xa3, 0xee, 0x14, 0x63, 0xa1, 0x86, 0x87, 0x6c, 0xd0, 0xa3, 0x20, 0x60, 0x7b, 0xb4, 0x94, 0x5e,
|
0x8d, 0xea, 0xea, 0xd5, 0xfe, 0x51, 0xbd, 0xb6, 0x96, 0xae, 0xb7, 0xd6, 0xdd, 0x5a, 0x06, 0x6a,
|
||||||
0x4d, 0x57, 0x8b, 0xb5, 0xb7, 0xad, 0x44, 0x62, 0x44, 0x74, 0xd6, 0xd7, 0x1c, 0x12, 0x47, 0x89,
|
0x05, 0xc8, 0x01, 0x3d, 0x89, 0x22, 0xb6, 0x43, 0x8d, 0xc2, 0x72, 0xa1, 0x51, 0x6b, 0xbe, 0x6d,
|
||||||
0xa1, 0x65, 0xc8, 0x52, 0xe6, 0x11, 0xbf, 0x94, 0xe1, 0xd6, 0x1d, 0xb9, 0x41, 0x2b, 0xa0, 0x53,
|
0xe7, 0xae, 0x54, 0x44, 0x67, 0xdf, 0xe7, 0x64, 0xba, 0x0a, 0x86, 0x16, 0xa0, 0x44, 0x59, 0x40,
|
||||||
0xe6, 0x05, 0x3d, 0x56, 0xca, 0x8a, 0x63, 0xb5, 0x53, 0xe7, 0x38, 0x8a, 0x4a, 0x7a, 0x7c, 0x8e,
|
0x42, 0xa3, 0xc8, 0xbd, 0xbb, 0x72, 0x82, 0x16, 0x41, 0xa7, 0x2c, 0x88, 0x7a, 0xcc, 0x28, 0x89,
|
||||||
0xa3, 0x08, 0x19, 0x90, 0x67, 0x38, 0xea, 0x12, 0xdf, 0xed, 0x94, 0x72, 0xab, 0x5a, 0x35, 0xef,
|
0x65, 0x35, 0x53, 0xeb, 0x38, 0x49, 0x0c, 0x3d, 0x5b, 0xc7, 0x49, 0x82, 0x4c, 0xa8, 0x30, 0x9c,
|
||||||
0xc4, 0x7b, 0xf4, 0x08, 0xa0, 0xb5, 0x8f, 0x5b, 0x07, 0x61, 0x40, 0x7c, 0x56, 0xca, 0xaf, 0x6a,
|
0x74, 0x49, 0xe8, 0x75, 0x8c, 0xf2, 0xb2, 0xd6, 0xa8, 0xb8, 0xd9, 0x1c, 0xdd, 0x05, 0xf0, 0x77,
|
||||||
0xd5, 0x62, 0xed, 0xf6, 0x68, 0x58, 0xf5, 0x18, 0x71, 0x27, 0x21, 0x8f, 0x2c, 0xc8, 0x05, 0x21,
|
0xb1, 0xbf, 0x17, 0x47, 0x24, 0x64, 0x46, 0x65, 0x59, 0x6b, 0xd4, 0x9a, 0xd7, 0x87, 0xc3, 0x5a,
|
||||||
0x23, 0x81, 0x4f, 0x4b, 0x05, 0xa1, 0xba, 0x6c, 0x49, 0x34, 0xad, 0x01, 0x9a, 0xd6, 0x63, 0xff,
|
0xcf, 0x18, 0x77, 0x73, 0x78, 0x64, 0x43, 0x39, 0x8a, 0x19, 0x89, 0x42, 0x6a, 0x54, 0x85, 0xe9,
|
||||||
0xd8, 0x19, 0x08, 0x99, 0x3b, 0x80, 0x92, 0x48, 0xd2, 0x30, 0xf0, 0x29, 0x7e, 0x2d, 0x28, 0x17,
|
0x82, 0x2d, 0xd9, 0xb4, 0x53, 0x36, 0xed, 0x7b, 0xe1, 0x81, 0x9b, 0x82, 0xac, 0x27, 0x80, 0xf2,
|
||||||
0x21, 0x1d, 0x12, 0xaf, 0x94, 0x5a, 0xd5, 0xaa, 0x0b, 0x0e, 0x5f, 0x9a, 0x6d, 0xb8, 0xbe, 0xcd,
|
0x4c, 0xd2, 0x38, 0x0a, 0x29, 0x7e, 0x2d, 0x2a, 0xe7, 0xa0, 0x10, 0x93, 0xc0, 0x98, 0x59, 0xd6,
|
||||||
0xdc, 0x88, 0xcd, 0x93, 0xa0, 0xf7, 0x21, 0x87, 0x8f, 0x70, 0xab, 0xa9, 0x2c, 0x17, 0xd6, 0xa0,
|
0x1a, 0xb3, 0x2e, 0x1f, 0x5a, 0x6d, 0xb8, 0xfc, 0x88, 0x79, 0x09, 0x9b, 0xe6, 0x82, 0xde, 0x87,
|
||||||
0x7f, 0x5a, 0xd1, 0x37, 0x8e, 0x70, 0xab, 0x51, 0x77, 0x74, 0xfe, 0xa9, 0xe1, 0x99, 0xef, 0xc1,
|
0x32, 0x7e, 0x81, 0xfd, 0x6d, 0xe5, 0xb9, 0xba, 0x0a, 0xfd, 0xa3, 0xba, 0xbe, 0xf1, 0x02, 0xfb,
|
||||||
0x82, 0x72, 0xa4, 0xe2, 0x57, 0xb1, 0x68, 0x67, 0xb1, 0x6c, 0xc2, 0x52, 0x1d, 0x77, 0xf0, 0xdc,
|
0xad, 0x75, 0x57, 0xe7, 0x9f, 0x5a, 0x81, 0xf5, 0x1e, 0xcc, 0xaa, 0x8d, 0x54, 0xfc, 0x2a, 0x16,
|
||||||
0x15, 0x63, 0xfe, 0xa6, 0xc1, 0x0d, 0x69, 0x29, 0xf6, 0xb6, 0x02, 0xa9, 0x58, 0x59, 0xef, 0x9f,
|
0xed, 0x38, 0x96, 0x4d, 0x98, 0x5f, 0xc7, 0x1d, 0x3c, 0x75, 0xc6, 0x58, 0xbf, 0x6a, 0x70, 0x45,
|
||||||
0x56, 0x52, 0x8d, 0xba, 0x93, 0x22, 0x17, 0x20, 0x82, 0x2a, 0x50, 0xc4, 0x47, 0x84, 0x35, 0x29,
|
0x7a, 0xca, 0x76, 0x5b, 0x84, 0x99, 0xcc, 0x58, 0xef, 0x1f, 0xd5, 0x67, 0x5a, 0xeb, 0xee, 0x0c,
|
||||||
0x73, 0x59, 0x8f, 0xd7, 0x1c, 0xff, 0x02, 0xfc, 0x68, 0x5b, 0x9c, 0xa0, 0xc7, 0x50, 0xe0, 0x3b,
|
0x39, 0x85, 0x11, 0x54, 0x87, 0x1a, 0x7e, 0x41, 0xd8, 0x36, 0x65, 0x1e, 0xeb, 0xf1, 0x9c, 0xe3,
|
||||||
0xec, 0x35, 0x5d, 0x26, 0x4a, 0xac, 0x58, 0x33, 0x46, 0x12, 0xf8, 0x6c, 0xf0, 0x1c, 0xd6, 0xf2,
|
0x5f, 0x80, 0x2f, 0x3d, 0x12, 0x2b, 0xe8, 0x1e, 0x54, 0xf9, 0x0c, 0x07, 0xdb, 0x1e, 0x13, 0x29,
|
||||||
0x27, 0xa7, 0x95, 0x6b, 0x2f, 0xff, 0xae, 0x68, 0x4e, 0x5e, 0xaa, 0x3d, 0x66, 0x66, 0x00, 0xcb,
|
0x56, 0x6b, 0x9a, 0x43, 0x17, 0xf8, 0x38, 0x7d, 0x0e, 0xab, 0x95, 0xc3, 0xa3, 0xfa, 0xa5, 0x97,
|
||||||
0x32, 0xbe, 0xad, 0x28, 0x68, 0x61, 0x4a, 0xaf, 0x1c, 0x7d, 0x0c, 0xb0, 0x89, 0xaf, 0x3e, 0xc9,
|
0x7f, 0xd5, 0x35, 0xb7, 0x22, 0xcd, 0xee, 0x31, 0x2b, 0x82, 0x05, 0x19, 0xdf, 0x56, 0x12, 0xf9,
|
||||||
0x1b, 0x50, 0x14, 0x6e, 0x14, 0xe8, 0x0f, 0x20, 0x17, 0xca, 0x0b, 0x0a, 0x17, 0x43, 0x6f, 0xe4,
|
0x98, 0xd2, 0x0b, 0x67, 0x1f, 0x03, 0x6c, 0xe2, 0x8b, 0xbf, 0xe4, 0x0d, 0xa8, 0x89, 0x6d, 0x14,
|
||||||
0xf0, 0x9e, 0x7a, 0x26, 0x03, 0x10, 0x06, 0xc2, 0xe6, 0x1d, 0x58, 0xfc, 0x8a, 0x50, 0xc6, 0xcb,
|
0xe9, 0xb7, 0xa1, 0x1c, 0xcb, 0x03, 0x8a, 0x2d, 0x06, 0xde, 0xc8, 0xfe, 0x4d, 0xf5, 0x4c, 0x52,
|
||||||
0x20, 0x86, 0x66, 0x05, 0xf4, 0x3d, 0xd2, 0x61, 0x38, 0x92, 0xd1, 0x3a, 0x6a, 0xc7, 0x8b, 0x26,
|
0x12, 0x52, 0xb0, 0xb5, 0x02, 0x73, 0x5f, 0x13, 0xca, 0x78, 0x1a, 0x64, 0xd4, 0x2c, 0x82, 0xbe,
|
||||||
0x21, 0x1b, 0xbf, 0x8d, 0xac, 0x20, 0xea, 0x92, 0x26, 0x18, 0x63, 0xb2, 0x5b, 0x29, 0x6a, 0xbe,
|
0x43, 0x3a, 0x0c, 0x27, 0x32, 0x5a, 0x57, 0xcd, 0x78, 0xd2, 0xe4, 0xb0, 0xd9, 0xdb, 0x28, 0x89,
|
||||||
0xd4, 0xa0, 0xf8, 0x25, 0xe9, 0x74, 0xae, 0x1a, 0x24, 0x41, 0x38, 0xa4, 0xcd, 0x69, 0x45, 0xd6,
|
0x12, 0x6f, 0x68, 0xa2, 0x62, 0x9c, 0xbd, 0xad, 0x84, 0x5a, 0x2f, 0x35, 0xa8, 0x7d, 0x45, 0x3a,
|
||||||
0x96, 0xda, 0xf1, 0x52, 0x74, 0x3b, 0x1d, 0x51, 0x51, 0x79, 0x87, 0x2f, 0xcd, 0x7f, 0x35, 0x40,
|
0x9d, 0x8b, 0x26, 0x49, 0x14, 0x1c, 0xd2, 0xe6, 0x65, 0x45, 0xe6, 0x96, 0x9a, 0xf1, 0x54, 0xf4,
|
||||||
0x5c, 0xf9, 0x0d, 0x54, 0x49, 0xcc, 0x89, 0xa9, 0x8b, 0x39, 0x31, 0x3d, 0x86, 0x13, 0x33, 0x63,
|
0x3a, 0x1d, 0x91, 0x51, 0x15, 0x97, 0x0f, 0xad, 0x7f, 0x34, 0x40, 0xdc, 0xf8, 0x0d, 0x64, 0x49,
|
||||||
0x39, 0x31, 0x3b, 0xc4, 0x89, 0x55, 0xc8, 0xd0, 0x10, 0xb7, 0x04, 0x8b, 0x8e, 0xa3, 0x34, 0x21,
|
0x56, 0x13, 0x67, 0x4e, 0xaf, 0x89, 0x85, 0x11, 0x35, 0xb1, 0x38, 0xb2, 0x26, 0x96, 0x06, 0x6a,
|
||||||
0x91, 0x44, 0x29, 0x37, 0xb6, 0x94, 0x6e, 0xc1, 0x5b, 0xe7, 0xae, 0x2e, 0x33, 0x6b, 0xfe, 0xaa,
|
0x62, 0x03, 0x8a, 0x34, 0xc6, 0xbe, 0xa8, 0xa2, 0xa3, 0x4a, 0x9a, 0x40, 0xe4, 0x59, 0x2a, 0x8f,
|
||||||
0xc1, 0xa2, 0x83, 0x29, 0xf9, 0x01, 0x6f, 0xb1, 0xe3, 0x2b, 0x4f, 0xd5, 0x32, 0x64, 0x5f, 0x10,
|
0x4c, 0xa5, 0x6b, 0xf0, 0xd6, 0x89, 0xa3, 0xcb, 0x9b, 0xb5, 0x7e, 0xd1, 0x60, 0xce, 0xc5, 0x94,
|
||||||
0x8f, 0xed, 0xab, 0x4c, 0xc9, 0x0d, 0x47, 0x67, 0x1f, 0x93, 0xf6, 0xbe, 0x7c, 0xfd, 0x0b, 0x8e,
|
0xfc, 0x80, 0xb7, 0xd8, 0xc1, 0x85, 0x5f, 0xd5, 0x02, 0x94, 0x9e, 0x93, 0x80, 0xed, 0xaa, 0x9b,
|
||||||
0xda, 0x99, 0x3f, 0xc1, 0x8d, 0xf5, 0x4e, 0x40, 0x71, 0xe3, 0xc9, 0xff, 0x11, 0x98, 0x4c, 0x67,
|
0x92, 0x13, 0xce, 0xce, 0x2e, 0x26, 0xed, 0x5d, 0xf9, 0xfa, 0x67, 0x5d, 0x35, 0xb3, 0x7e, 0x82,
|
||||||
0x5a, 0x64, 0x41, 0x6e, 0xcc, 0x2f, 0x60, 0x71, 0xcb, 0xed, 0xd1, 0xb9, 0xf9, 0x73, 0x13, 0x96,
|
0x2b, 0x6b, 0x9d, 0x88, 0xe2, 0xd6, 0x83, 0xff, 0x23, 0x30, 0x79, 0x9d, 0x05, 0x71, 0x0b, 0x72,
|
||||||
0x1c, 0x4c, 0x7b, 0xdd, 0xb9, 0x0d, 0x6d, 0xc0, 0x4d, 0xfe, 0x38, 0xb7, 0x88, 0x37, 0x4f, 0xf1,
|
0x62, 0x7d, 0x09, 0x73, 0x5b, 0x5e, 0x8f, 0x4e, 0x5d, 0x3f, 0x37, 0x61, 0xde, 0xc5, 0xb4, 0xd7,
|
||||||
0x9a, 0x1f, 0x48, 0x3e, 0x90, 0x66, 0xd4, 0x13, 0x47, 0x90, 0x09, 0x89, 0x27, 0x5f, 0xf8, 0x82,
|
0x9d, 0xda, 0xd1, 0x06, 0x5c, 0xe5, 0x8f, 0x73, 0x8b, 0x04, 0xd3, 0x24, 0xaf, 0xf5, 0x81, 0xac,
|
||||||
0x23, 0xd6, 0xe6, 0x5f, 0x1a, 0xdc, 0x5a, 0x8f, 0xfb, 0xec, 0xbc, 0x73, 0x47, 0x13, 0x96, 0x42,
|
0x07, 0xd2, 0x8d, 0x7a, 0xe2, 0x08, 0x8a, 0x31, 0x09, 0xe4, 0x0b, 0x9f, 0x75, 0xc5, 0xd8, 0xfa,
|
||||||
0x37, 0xc2, 0x3e, 0x6b, 0x26, 0x7a, 0xbd, 0x4c, 0x49, 0x8d, 0x73, 0xfa, 0x9f, 0xa7, 0x95, 0x3b,
|
0x53, 0x83, 0x6b, 0x6b, 0x59, 0x9f, 0x9d, 0x56, 0x77, 0x6c, 0xc3, 0x7c, 0xec, 0x25, 0x38, 0x64,
|
||||||
0x89, 0x09, 0x2a, 0x08, 0xb1, 0x1f, 0xab, 0x53, 0xbb, 0x1d, 0xdc, 0xf5, 0x48, 0x1b, 0x53, 0x66,
|
0xdb, 0xb9, 0x5e, 0x2f, 0xaf, 0xa4, 0xc9, 0x6b, 0xfa, 0x1f, 0x47, 0xf5, 0x95, 0x9c, 0x82, 0x8a,
|
||||||
0xd5, 0xc5, 0x2f, 0x67, 0x51, 0x1a, 0x5b, 0xbf, 0x70, 0x0e, 0x48, 0xcf, 0x32, 0x07, 0x7c, 0x07,
|
0x62, 0x1c, 0x66, 0xe6, 0xd4, 0x69, 0x47, 0x37, 0x02, 0xd2, 0xc6, 0x94, 0xd9, 0xeb, 0xe2, 0x3f,
|
||||||
0x2b, 0xc3, 0xb7, 0x53, 0x60, 0x7c, 0x0e, 0xc5, 0xb3, 0xe9, 0xee, 0x42, 0xd6, 0x1b, 0x19, 0x48,
|
0x77, 0x4e, 0x3a, 0x5b, 0x3b, 0x55, 0x07, 0x14, 0x26, 0xd1, 0x01, 0xdf, 0xc1, 0xe2, 0xe0, 0xe9,
|
||||||
0x92, 0x0a, 0xe6, 0x8f, 0xb0, 0xf4, 0x4d, 0xe8, 0xbd, 0x81, 0x59, 0xad, 0x06, 0x85, 0x08, 0xd3,
|
0x14, 0x19, 0x5f, 0x40, 0xed, 0x58, 0xdd, 0x9d, 0x5a, 0xf5, 0x86, 0x04, 0x49, 0xde, 0xc0, 0xfa,
|
||||||
0xa0, 0x17, 0xb5, 0x30, 0x15, 0x58, 0x8d, 0xbb, 0xd4, 0x99, 0x58, 0xed, 0x97, 0x22, 0x64, 0x05,
|
0x11, 0xe6, 0xbf, 0x89, 0x83, 0x37, 0xa0, 0xd5, 0x9a, 0x50, 0x4d, 0x30, 0x8d, 0x7a, 0x89, 0x8f,
|
||||||
0x7d, 0xa3, 0x03, 0xd0, 0xe5, 0xa0, 0x83, 0x6c, 0x6b, 0xd2, 0xf0, 0x6d, 0x8d, 0x0c, 0x96, 0xc6,
|
0xa9, 0xe0, 0x6a, 0xd4, 0xa1, 0x8e, 0x61, 0xd6, 0x0a, 0x5c, 0xb9, 0x2f, 0x45, 0x6d, 0xba, 0xb3,
|
||||||
0x27, 0xb3, 0x2b, 0x28, 0xcc, 0xbe, 0x87, 0xac, 0x18, 0x48, 0xd0, 0x9d, 0xc9, 0xaa, 0xc9, 0xf1,
|
0x01, 0x65, 0x59, 0xdd, 0xe5, 0x51, 0xaa, 0x6e, 0x3a, 0xe5, 0x09, 0x95, 0x61, 0xb3, 0x5a, 0x5f,
|
||||||
0xc8, 0xf8, 0x68, 0x26, 0x59, 0xe5, 0xa1, 0x0d, 0xba, 0xec, 0xf2, 0xd3, 0xae, 0x33, 0x32, 0xf5,
|
0x56, 0x9a, 0x58, 0x9d, 0xdb, 0x38, 0x45, 0x1f, 0x0a, 0x80, 0x9b, 0x02, 0x9b, 0xff, 0xd6, 0xa0,
|
||||||
0x18, 0x1f, 0xcf, 0xa2, 0x10, 0x3b, 0x7a, 0x0e, 0x0b, 0xe7, 0xc6, 0x09, 0x54, 0x9b, 0x45, 0xfd,
|
0x24, 0x3a, 0x06, 0xda, 0x03, 0x5d, 0x6a, 0x2b, 0xe4, 0xd8, 0x67, 0xfd, 0x52, 0xb0, 0x87, 0xb4,
|
||||||
0x7c, 0x57, 0xb9, 0xa4, 0xcb, 0x1d, 0x48, 0x6f, 0x62, 0x86, 0xaa, 0x93, 0x95, 0xce, 0x66, 0x0e,
|
0xac, 0xf9, 0xc9, 0xe4, 0x06, 0x2a, 0xd4, 0xef, 0xa1, 0x24, 0x34, 0x10, 0x5a, 0x39, 0xdb, 0x34,
|
||||||
0xe3, 0xc3, 0x19, 0x24, 0x63, 0xdc, 0x32, 0xfc, 0xb9, 0x23, 0x6b, 0xb2, 0xca, 0xf0, 0x88, 0x60,
|
0xaf, 0xc8, 0xcc, 0x8f, 0x26, 0xc2, 0xaa, 0x1d, 0xda, 0xa0, 0x4b, 0x61, 0x31, 0xee, 0x38, 0x43,
|
||||||
0xd8, 0x33, 0xcb, 0x2b, 0x47, 0x0d, 0xc8, 0xf0, 0x8e, 0x8f, 0xa6, 0xc4, 0x96, 0x98, 0x0a, 0x8c,
|
0x42, 0xcb, 0xfc, 0x78, 0x12, 0x83, 0x6c, 0xa3, 0x67, 0x30, 0x7b, 0x42, 0xc1, 0xa0, 0xe6, 0x24,
|
||||||
0x95, 0x91, 0x6a, 0xde, 0xe0, 0x7f, 0xf7, 0xa1, 0x2d, 0xc8, 0x70, 0x8a, 0x46, 0x53, 0xea, 0x70,
|
0xe6, 0x27, 0x1b, 0xd9, 0x39, 0xb7, 0x7c, 0x02, 0x85, 0x4d, 0xcc, 0x50, 0xe3, 0x6c, 0xa3, 0x63,
|
||||||
0xb4, 0x9b, 0x8f, 0xb5, 0xb8, 0x0d, 0x85, 0xb8, 0xd1, 0x4d, 0x83, 0x62, 0xb8, 0x23, 0x8e, 0x35,
|
0x99, 0x63, 0x7e, 0x38, 0x01, 0x32, 0xe3, 0xad, 0xc8, 0x2b, 0x0c, 0xb2, 0xcf, 0x36, 0x19, 0x54,
|
||||||
0xfa, 0x04, 0x72, 0xaa, 0x45, 0xa1, 0x29, 0xf9, 0x3e, 0xdf, 0xc9, 0x26, 0x18, 0xcc, 0x8a, 0x96,
|
0x25, 0xa6, 0x33, 0x31, 0x5e, 0x6d, 0xd4, 0x82, 0x22, 0x17, 0x19, 0x68, 0x4c, 0x6c, 0x39, 0x21,
|
||||||
0x33, 0x2d, 0xc2, 0xe1, 0xbe, 0x34, 0xd6, 0xe0, 0x53, 0xd0, 0x65, 0xef, 0x99, 0xf6, 0x68, 0x46,
|
0x62, 0x2e, 0x0e, 0x3d, 0xa0, 0x0d, 0xfe, 0x23, 0x15, 0x6d, 0x41, 0x91, 0x77, 0x05, 0x34, 0x26,
|
||||||
0x3a, 0xd4, 0x58, 0x93, 0x04, 0xf2, 0x83, 0xf6, 0x81, 0xee, 0x4e, 0xaf, 0x91, 0x44, 0xb7, 0x32,
|
0x0f, 0x87, 0x05, 0xc4, 0x48, 0x8f, 0x8f, 0xa0, 0x9a, 0xf5, 0xd6, 0x71, 0x54, 0x0c, 0x36, 0xe1,
|
||||||
0xac, 0x59, 0xc5, 0x55, 0x45, 0xbd, 0x00, 0x48, 0x10, 0xfc, 0xfd, 0x29, 0x10, 0x5f, 0xd4, 0xaa,
|
0x91, 0x4e, 0x1f, 0x40, 0x59, 0x75, 0x45, 0x34, 0xe6, 0xbe, 0x4f, 0x36, 0xcf, 0x33, 0x1c, 0x96,
|
||||||
0x8c, 0x4f, 0x2f, 0xa7, 0xa4, 0x1c, 0x3f, 0x05, 0x5d, 0x32, 0xf8, 0x34, 0xd8, 0x46, 0x78, 0x7e,
|
0x44, 0x97, 0x1b, 0x17, 0xe1, 0x60, 0x2b, 0x1c, 0xe9, 0xf0, 0x21, 0xe8, 0xb2, 0xdd, 0x8d, 0x7b,
|
||||||
0x1c, 0x6c, 0x6b, 0xdf, 0x9e, 0xbc, 0x2a, 0x5f, 0xfb, 0xe3, 0x55, 0xf9, 0xda, 0xcf, 0xfd, 0xb2,
|
0x34, 0x43, 0x4d, 0x71, 0xa4, 0x4b, 0x02, 0x95, 0xb4, 0x63, 0xa1, 0x1b, 0xe3, 0x73, 0x24, 0xd7,
|
||||||
0x76, 0xd2, 0x2f, 0x6b, 0xbf, 0xf7, 0xcb, 0xda, 0x3f, 0xfd, 0xb2, 0xb6, 0xf3, 0xe8, 0xf5, 0xfe,
|
0x20, 0x4d, 0x7b, 0x52, 0xb8, 0xca, 0xa8, 0xe7, 0x00, 0xb9, 0x9e, 0x72, 0x6b, 0x0c, 0xc5, 0xa7,
|
||||||
0xbb, 0xf2, 0x50, 0x2c, 0x76, 0x75, 0xe1, 0xe7, 0xfe, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17,
|
0x75, 0x47, 0xf3, 0xd3, 0xf3, 0x19, 0xa9, 0x8d, 0x1f, 0x82, 0x2e, 0x9b, 0xc6, 0x38, 0xda, 0x86,
|
||||||
0xec, 0xf8, 0x44, 0xa4, 0x11, 0x00, 0x00,
|
0x5a, 0xcb, 0x48, 0xda, 0x76, 0xa0, 0xac, 0xca, 0xfb, 0xb8, 0x5c, 0x39, 0xd9, 0x31, 0xcc, 0x1b,
|
||||||
|
0x13, 0xa2, 0x65, 0xe8, 0xab, 0xdf, 0x1e, 0xbe, 0x5a, 0xba, 0xf4, 0xfb, 0xab, 0xa5, 0x4b, 0x3f,
|
||||||
|
0xf7, 0x97, 0xb4, 0xc3, 0xfe, 0x92, 0xf6, 0x5b, 0x7f, 0x49, 0xfb, 0xbb, 0xbf, 0xa4, 0x3d, 0xb9,
|
||||||
|
0xfb, 0x7a, 0x7f, 0x72, 0xba, 0x23, 0x06, 0x4f, 0x75, 0x71, 0x9e, 0x5b, 0xff, 0x05, 0x00, 0x00,
|
||||||
|
0xff, 0xff, 0x5e, 0xf6, 0xae, 0x85, 0xb9, 0x12, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import "google/protobuf/empty.proto";
|
||||||
import "google/protobuf/any.proto";
|
import "google/protobuf/any.proto";
|
||||||
import "gogoproto/gogo.proto";
|
import "gogoproto/gogo.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/metrics.proto";
|
||||||
import "github.com/containerd/containerd/api/types/descriptor.proto";
|
import "github.com/containerd/containerd/api/types/descriptor.proto";
|
||||||
import "github.com/containerd/containerd/api/types/task/task.proto";
|
import "github.com/containerd/containerd/api/types/task/task.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
|
@ -46,6 +47,8 @@ service Tasks {
|
||||||
rpc Checkpoint(CheckpointTaskRequest) returns (CheckpointTaskResponse);
|
rpc Checkpoint(CheckpointTaskRequest) returns (CheckpointTaskResponse);
|
||||||
|
|
||||||
rpc Update(UpdateTaskRequest) returns (google.protobuf.Empty);
|
rpc Update(UpdateTaskRequest) returns (google.protobuf.Empty);
|
||||||
|
|
||||||
|
rpc Metrics(MetricsRequest) returns (MetricsResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateTaskRequest {
|
message CreateTaskRequest {
|
||||||
|
@ -183,3 +186,11 @@ message UpdateTaskRequest {
|
||||||
string container_id = 1;
|
string container_id = 1;
|
||||||
google.protobuf.Any resources = 2;
|
google.protobuf.Any resources = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message MetricsRequest {
|
||||||
|
repeated string filters = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MetricsResponse {
|
||||||
|
repeated types.Metric metrics = 1;
|
||||||
|
}
|
||||||
|
|
|
@ -7,10 +7,12 @@
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
github.com/containerd/containerd/api/types/descriptor.proto
|
github.com/containerd/containerd/api/types/descriptor.proto
|
||||||
|
github.com/containerd/containerd/api/types/metrics.proto
|
||||||
github.com/containerd/containerd/api/types/mount.proto
|
github.com/containerd/containerd/api/types/mount.proto
|
||||||
|
|
||||||
It has these top-level messages:
|
It has these top-level messages:
|
||||||
Descriptor
|
Descriptor
|
||||||
|
Metric
|
||||||
Mount
|
Mount
|
||||||
*/
|
*/
|
||||||
package types
|
package types
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
// Code generated by protoc-gen-gogo.
|
||||||
|
// source: github.com/containerd/containerd/api/types/metrics.proto
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import proto "github.com/gogo/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
import _ "github.com/gogo/protobuf/gogoproto"
|
||||||
|
import google_protobuf1 "github.com/gogo/protobuf/types"
|
||||||
|
import _ "github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
|
import time "time"
|
||||||
|
|
||||||
|
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
|
import strings "strings"
|
||||||
|
import reflect "reflect"
|
||||||
|
|
||||||
|
import io "io"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
var _ = time.Kitchen
|
||||||
|
|
||||||
|
type Metric struct {
|
||||||
|
Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,stdtime" json:"timestamp"`
|
||||||
|
ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Data *google_protobuf1.Any `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metric) Reset() { *m = Metric{} }
|
||||||
|
func (*Metric) ProtoMessage() {}
|
||||||
|
func (*Metric) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{0} }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Metric)(nil), "containerd.types.Metric")
|
||||||
|
}
|
||||||
|
func (m *Metric) 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 *Metric) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
var i int
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
i++
|
||||||
|
i = encodeVarintMetrics(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)))
|
||||||
|
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i += n1
|
||||||
|
if len(m.ID) > 0 {
|
||||||
|
dAtA[i] = 0x12
|
||||||
|
i++
|
||||||
|
i = encodeVarintMetrics(dAtA, i, uint64(len(m.ID)))
|
||||||
|
i += copy(dAtA[i:], m.ID)
|
||||||
|
}
|
||||||
|
if m.Data != nil {
|
||||||
|
dAtA[i] = 0x1a
|
||||||
|
i++
|
||||||
|
i = encodeVarintMetrics(dAtA, i, uint64(m.Data.Size()))
|
||||||
|
n2, err := m.Data.MarshalTo(dAtA[i:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i += n2
|
||||||
|
}
|
||||||
|
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 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 encodeVarintMetrics(dAtA []byte, offset int, v uint64) int {
|
||||||
|
for v >= 1<<7 {
|
||||||
|
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||||
|
v >>= 7
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
dAtA[offset] = uint8(v)
|
||||||
|
return offset + 1
|
||||||
|
}
|
||||||
|
func (m *Metric) Size() (n int) {
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
|
||||||
|
n += 1 + l + sovMetrics(uint64(l))
|
||||||
|
l = len(m.ID)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovMetrics(uint64(l))
|
||||||
|
}
|
||||||
|
if m.Data != nil {
|
||||||
|
l = m.Data.Size()
|
||||||
|
n += 1 + l + sovMetrics(uint64(l))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func sovMetrics(x uint64) (n int) {
|
||||||
|
for {
|
||||||
|
n++
|
||||||
|
x >>= 7
|
||||||
|
if x == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
func sozMetrics(x uint64) (n int) {
|
||||||
|
return sovMetrics(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||||
|
}
|
||||||
|
func (this *Metric) String() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
s := strings.Join([]string{`&Metric{`,
|
||||||
|
`Timestamp:` + strings.Replace(strings.Replace(this.Timestamp.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||||
|
`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
|
||||||
|
`Data:` + strings.Replace(fmt.Sprintf("%v", this.Data), "Any", "google_protobuf1.Any", 1) + `,`,
|
||||||
|
`}`,
|
||||||
|
}, "")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
func valueToStringMetrics(v interface{}) string {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
if rv.IsNil() {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
pv := reflect.Indirect(rv).Interface()
|
||||||
|
return fmt.Sprintf("*%v", pv)
|
||||||
|
}
|
||||||
|
func (m *Metric) 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: Metric: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: Metric: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", 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
|
||||||
|
}
|
||||||
|
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 2:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field ID", 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.ID = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 3:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Data", 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
|
||||||
|
}
|
||||||
|
if m.Data == nil {
|
||||||
|
m.Data = &google_protobuf1.Any{}
|
||||||
|
}
|
||||||
|
if err := m.Data.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
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) {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowMetrics
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
switch wireType {
|
||||||
|
case 0:
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowMetrics
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx++
|
||||||
|
if dAtA[iNdEx-1] < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 1:
|
||||||
|
iNdEx += 8
|
||||||
|
return iNdEx, nil
|
||||||
|
case 2:
|
||||||
|
var length int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowMetrics
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
length |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iNdEx += length
|
||||||
|
if length < 0 {
|
||||||
|
return 0, ErrInvalidLengthMetrics
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 3:
|
||||||
|
for {
|
||||||
|
var innerWire uint64
|
||||||
|
var start int = iNdEx
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowMetrics
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
innerWire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
innerWireType := int(innerWire & 0x7)
|
||||||
|
if innerWireType == 4 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
next, err := skipMetrics(dAtA[start:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
iNdEx = start + next
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 4:
|
||||||
|
return iNdEx, nil
|
||||||
|
case 5:
|
||||||
|
iNdEx += 4
|
||||||
|
return iNdEx, nil
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidLengthMetrics = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||||
|
ErrIntOverflowMetrics = fmt.Errorf("proto: integer overflow")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/containerd/containerd/api/types/metrics.proto", fileDescriptorMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptorMetrics = []byte{
|
||||||
|
// 256 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x48, 0xcf, 0x2c, 0xc9,
|
||||||
|
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d,
|
||||||
|
0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xe7, 0xa6, 0x96,
|
||||||
|
0x14, 0x65, 0x26, 0x17, 0xeb, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0xd4, 0xe8, 0x81,
|
||||||
|
0xe5, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x94, 0x64,
|
||||||
|
0x7a, 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x3e, 0x98, 0x97, 0x54, 0x9a, 0xa6, 0x9f, 0x98, 0x57, 0x09,
|
||||||
|
0x95, 0x92, 0x47, 0x97, 0x2a, 0xc9, 0xcc, 0x4d, 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0x80, 0x28, 0x50,
|
||||||
|
0xea, 0x63, 0xe4, 0x62, 0xf3, 0x05, 0xdb, 0x2a, 0xe4, 0xc4, 0xc5, 0x09, 0x97, 0x95, 0x60, 0x54,
|
||||||
|
0x60, 0xd4, 0xe0, 0x36, 0x92, 0xd2, 0x83, 0xe8, 0xd7, 0x83, 0xe9, 0xd7, 0x0b, 0x81, 0xa9, 0x70,
|
||||||
|
0xe2, 0x38, 0x71, 0x4f, 0x9e, 0x61, 0xc2, 0x7d, 0x79, 0xc6, 0x20, 0x84, 0x36, 0x21, 0x31, 0x2e,
|
||||||
|
0xa6, 0xcc, 0x14, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xb6, 0x47, 0xf7, 0xe4, 0x99, 0x3c,
|
||||||
|
0x5d, 0x82, 0x98, 0x32, 0x53, 0x84, 0x34, 0xb8, 0x58, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1,
|
||||||
|
0xc6, 0x8a, 0x60, 0x18, 0xeb, 0x98, 0x57, 0x19, 0x04, 0x56, 0xe1, 0xe4, 0x75, 0xe2, 0xa1, 0x1c,
|
||||||
|
0xc3, 0x8d, 0x87, 0x72, 0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48,
|
||||||
|
0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x28, 0x03, 0xe2, 0x03, 0xd2, 0x1a, 0x4c, 0x26, 0xb1, 0x81,
|
||||||
|
0xcd, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x51, 0x36, 0x74, 0x83, 0x01, 0x00, 0x00,
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package containerd.types;
|
||||||
|
|
||||||
|
import "gogoproto/gogo.proto";
|
||||||
|
import "google/protobuf/any.proto";
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
option go_package = "github.com/containerd/containerd/api/types;types";
|
||||||
|
|
||||||
|
message Metric {
|
||||||
|
google.protobuf.Timestamp timestamp = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||||
|
string id = 2;
|
||||||
|
google.protobuf.Any data = 3;
|
||||||
|
}
|
|
@ -17,6 +17,11 @@ import proto "github.com/gogo/protobuf/proto"
|
||||||
import fmt "fmt"
|
import fmt "fmt"
|
||||||
import math "math"
|
import math "math"
|
||||||
import _ "github.com/gogo/protobuf/gogoproto"
|
import _ "github.com/gogo/protobuf/gogoproto"
|
||||||
|
import _ "github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
|
import time "time"
|
||||||
|
|
||||||
|
import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
import strings "strings"
|
import strings "strings"
|
||||||
import reflect "reflect"
|
import reflect "reflect"
|
||||||
|
@ -27,6 +32,7 @@ import io "io"
|
||||||
var _ = proto.Marshal
|
var _ = proto.Marshal
|
||||||
var _ = fmt.Errorf
|
var _ = fmt.Errorf
|
||||||
var _ = math.Inf
|
var _ = math.Inf
|
||||||
|
var _ = time.Kitchen
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
// is compatible with the proto package it is being compiled against.
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
@ -77,6 +83,7 @@ type Process struct {
|
||||||
Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"`
|
Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"`
|
||||||
Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"`
|
Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"`
|
||||||
ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"`
|
ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"`
|
||||||
|
ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Process) Reset() { *m = Process{} }
|
func (m *Process) Reset() { *m = Process{} }
|
||||||
|
@ -157,6 +164,14 @@ func (m *Process) MarshalTo(dAtA []byte) (int, error) {
|
||||||
i++
|
i++
|
||||||
i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus))
|
i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus))
|
||||||
}
|
}
|
||||||
|
dAtA[i] = 0x52
|
||||||
|
i++
|
||||||
|
i = encodeVarintTask(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)))
|
||||||
|
n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i += n1
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +237,8 @@ func (m *Process) Size() (n int) {
|
||||||
if m.ExitStatus != 0 {
|
if m.ExitStatus != 0 {
|
||||||
n += 1 + sovTask(uint64(m.ExitStatus))
|
n += 1 + sovTask(uint64(m.ExitStatus))
|
||||||
}
|
}
|
||||||
|
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt)
|
||||||
|
n += 1 + l + sovTask(uint64(l))
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +269,7 @@ func (this *Process) String() string {
|
||||||
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
|
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
|
||||||
`Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`,
|
`Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`,
|
||||||
`ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`,
|
`ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`,
|
||||||
|
`ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf1.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
}, "")
|
}, "")
|
||||||
return s
|
return s
|
||||||
|
@ -515,6 +533,36 @@ func (m *Process) Unmarshal(dAtA []byte) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 10:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field ExitedAt", wireType)
|
||||||
|
}
|
||||||
|
var msglen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowTask
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
msglen |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if msglen < 0 {
|
||||||
|
return ErrInvalidLengthTask
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + msglen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
default:
|
default:
|
||||||
iNdEx = preIndex
|
iNdEx = preIndex
|
||||||
skippy, err := skipTask(dAtA[iNdEx:])
|
skippy, err := skipTask(dAtA[iNdEx:])
|
||||||
|
@ -646,33 +694,37 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorTask = []byte{
|
var fileDescriptorTask = []byte{
|
||||||
// 447 bytes of a gzipped FileDescriptorProto
|
// 503 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x4f, 0x6f, 0xd3, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x3d, 0x6f, 0xd3, 0x40,
|
||||||
0x18, 0xc6, 0xeb, 0x74, 0x4d, 0x3b, 0x77, 0x1b, 0xc1, 0x4c, 0x93, 0x55, 0x90, 0x1b, 0x71, 0xaa,
|
0x1c, 0xc6, 0x73, 0x6e, 0xe3, 0x24, 0x97, 0xb6, 0x98, 0xa3, 0xaa, 0x2c, 0x83, 0x6c, 0x8b, 0x29,
|
||||||
0x38, 0xa4, 0x62, 0xbb, 0x71, 0xdb, 0x9a, 0x0a, 0x55, 0x48, 0x59, 0xe4, 0xae, 0xe2, 0x38, 0x65,
|
0x62, 0xb0, 0x45, 0xba, 0xb1, 0xe5, 0x4d, 0x28, 0x42, 0x72, 0xa3, 0x4b, 0x22, 0xc6, 0xc8, 0xc9,
|
||||||
0xb5, 0x15, 0xac, 0x31, 0x3b, 0x72, 0x1c, 0xfe, 0xdc, 0x38, 0xa2, 0x7d, 0x87, 0x89, 0x03, 0x7c,
|
0x1d, 0xe6, 0xd4, 0xe6, 0xce, 0xb2, 0xcf, 0xbc, 0x6c, 0x8c, 0xa8, 0x13, 0x5f, 0xa0, 0x13, 0x7c,
|
||||||
0x0a, 0x3e, 0xc1, 0x8e, 0x9c, 0x10, 0xa7, 0x89, 0xe5, 0x93, 0x20, 0x27, 0xa1, 0xe4, 0xc0, 0x25,
|
0x0a, 0x3e, 0x41, 0x46, 0x26, 0xc4, 0x14, 0xa8, 0x3f, 0x09, 0x3a, 0xdb, 0x09, 0x19, 0x58, 0xac,
|
||||||
0x7a, 0xde, 0xe7, 0xf7, 0xbc, 0x6f, 0x9e, 0x48, 0x81, 0x2f, 0x52, 0x61, 0xde, 0x14, 0x17, 0xc1,
|
0x7b, 0x9e, 0xdf, 0x73, 0x8f, 0xff, 0xf7, 0x87, 0x2f, 0x22, 0x26, 0xdf, 0x66, 0x4b, 0x6f, 0x25,
|
||||||
0x5a, 0x5d, 0x4d, 0xd7, 0x4a, 0x9a, 0x44, 0x48, 0xae, 0x59, 0x5b, 0x26, 0x99, 0x98, 0x9a, 0x8f,
|
0xd6, 0xfe, 0x4a, 0x70, 0x19, 0x32, 0x4e, 0x13, 0x72, 0x78, 0x0c, 0x63, 0xe6, 0xcb, 0x8f, 0x31,
|
||||||
0x19, 0xcf, 0xa7, 0x26, 0xc9, 0x2f, 0xab, 0x47, 0x90, 0x69, 0x65, 0x14, 0x7a, 0xf4, 0x2f, 0x15,
|
0x4d, 0x7d, 0x19, 0xa6, 0xd7, 0xc5, 0xc7, 0x8b, 0x13, 0x21, 0x05, 0x7a, 0xf4, 0x2f, 0xe5, 0xbd,
|
||||||
0xbc, 0x7b, 0x1e, 0x54, 0xa1, 0xd1, 0x7e, 0xaa, 0x52, 0x55, 0xf1, 0xa9, 0x55, 0x75, 0xf4, 0xe9,
|
0x7b, 0xee, 0x15, 0x21, 0xeb, 0x3c, 0x12, 0x91, 0x28, 0xb8, 0xaf, 0x4e, 0x65, 0xd4, 0x72, 0x22,
|
||||||
0x17, 0x07, 0xf6, 0x63, 0xad, 0xd6, 0x3c, 0xcf, 0xd1, 0x21, 0xdc, 0xd9, 0x2c, 0x9e, 0x0b, 0x86,
|
0x21, 0xa2, 0x1b, 0xea, 0x17, 0x6a, 0x99, 0xbd, 0xf1, 0x25, 0x5b, 0xd3, 0x54, 0x86, 0xeb, 0xb8,
|
||||||
0x81, 0x0f, 0x26, 0xdb, 0x27, 0x0f, 0xca, 0xbb, 0xf1, 0x70, 0xf6, 0xd7, 0x5f, 0x84, 0x74, 0xb8,
|
0x0c, 0x3c, 0xcd, 0x35, 0xd8, 0x98, 0x24, 0x62, 0x45, 0xd3, 0x14, 0x75, 0xe1, 0xc9, 0xbe, 0x79,
|
||||||
0x09, 0x2d, 0x18, 0x3a, 0x80, 0x8e, 0x60, 0xd8, 0xa9, 0x92, 0x6e, 0x79, 0x37, 0x76, 0x16, 0x21,
|
0xc1, 0x88, 0x09, 0x5c, 0xd0, 0x69, 0xf5, 0x1f, 0xe4, 0x5b, 0xa7, 0x3d, 0xd8, 0xf9, 0xe3, 0x21,
|
||||||
0x75, 0x04, 0x43, 0x1e, 0xec, 0x66, 0x82, 0xe1, 0xae, 0x0f, 0x26, 0xbb, 0xd4, 0x4a, 0x74, 0x04,
|
0x6e, 0xef, 0x43, 0x63, 0x82, 0x2e, 0xa0, 0xc6, 0x88, 0xa9, 0x15, 0x49, 0x3d, 0xdf, 0x3a, 0xda,
|
||||||
0xdd, 0xdc, 0x24, 0xa6, 0xc8, 0xf1, 0x96, 0x0f, 0x26, 0x7b, 0x87, 0x8f, 0x83, 0xff, 0xb4, 0x0c,
|
0x78, 0x88, 0x35, 0x46, 0x90, 0x01, 0x8f, 0x62, 0x46, 0xcc, 0x23, 0x17, 0x74, 0x4e, 0xb1, 0x3a,
|
||||||
0x96, 0x55, 0x84, 0x36, 0x51, 0xb4, 0x0f, 0x7b, 0xb9, 0x61, 0x42, 0xe2, 0x9e, 0x7d, 0x03, 0xad,
|
0xa2, 0x4b, 0xa8, 0xa7, 0x32, 0x94, 0x59, 0x6a, 0x1e, 0xbb, 0xa0, 0x73, 0xd6, 0x7d, 0xec, 0xfd,
|
||||||
0x07, 0x74, 0x60, 0x4f, 0x31, 0x55, 0x18, 0xec, 0x56, 0x76, 0x33, 0x35, 0x3e, 0xd7, 0x1a, 0xf7,
|
0xe7, 0x19, 0xde, 0xb4, 0x88, 0xe0, 0x2a, 0x8a, 0xce, 0x61, 0x3d, 0x95, 0x84, 0x71, 0xb3, 0xae,
|
||||||
0x37, 0x3e, 0xd7, 0x1a, 0x8d, 0xe0, 0xc0, 0x70, 0x7d, 0x25, 0x64, 0xf2, 0x16, 0x0f, 0x7c, 0x30,
|
0xfe, 0x80, 0x4b, 0x81, 0x2e, 0x54, 0x15, 0x11, 0x99, 0x34, 0xf5, 0xc2, 0xae, 0x54, 0xe5, 0xd3,
|
||||||
0x19, 0xd0, 0xcd, 0x8c, 0xc6, 0x70, 0xc8, 0x3f, 0x08, 0x73, 0xde, 0x74, 0xdb, 0xae, 0x0a, 0x43,
|
0x24, 0x31, 0x1b, 0x7b, 0x9f, 0x26, 0x09, 0xb2, 0x60, 0x53, 0xd2, 0x64, 0xcd, 0x78, 0x78, 0x63,
|
||||||
0x6b, 0xd5, 0x55, 0x9e, 0xfd, 0x04, 0xd0, 0xad, 0x25, 0x22, 0xb0, 0xbf, 0x8a, 0x5e, 0x45, 0xa7,
|
0x36, 0x5d, 0xd0, 0x69, 0xe2, 0xbd, 0x46, 0x0e, 0x6c, 0xd3, 0x0f, 0x4c, 0x2e, 0xaa, 0xd9, 0x5a,
|
||||||
0xaf, 0x23, 0xaf, 0x33, 0x7a, 0x78, 0x7d, 0xe3, 0xef, 0xd6, 0x60, 0x25, 0x2f, 0xa5, 0x7a, 0x2f,
|
0xc5, 0xc0, 0x50, 0x59, 0xe5, 0x28, 0xa8, 0x07, 0x5b, 0x4a, 0x51, 0xb2, 0x08, 0xa5, 0x09, 0x5d,
|
||||||
0x2d, 0x9f, 0xd1, 0xf9, 0xf1, 0xd9, 0x3c, 0xf4, 0x40, 0x9b, 0xcf, 0x34, 0x4f, 0x0c, 0x67, 0x96,
|
0xd0, 0x69, 0x77, 0x2d, 0xaf, 0x5c, 0xab, 0xb7, 0x5b, 0xab, 0x37, 0xdb, 0xad, 0xb5, 0xdf, 0xdc,
|
||||||
0xd3, 0x55, 0x14, 0x2d, 0xa2, 0x97, 0x9e, 0xd3, 0xe6, 0xb4, 0x90, 0x52, 0xc8, 0xd4, 0xf2, 0xe5,
|
0x6c, 0x9d, 0xda, 0x97, 0xdf, 0x0e, 0xc0, 0xcd, 0xf2, 0x5a, 0x4f, 0x3e, 0xfb, 0x09, 0xa0, 0x5e,
|
||||||
0xd9, 0x69, 0x1c, 0xcf, 0x43, 0xaf, 0xdb, 0xe6, 0x4b, 0xa3, 0xb2, 0x8c, 0x33, 0xf4, 0x04, 0xba,
|
0xb5, 0xd9, 0xb0, 0x31, 0x0f, 0x5e, 0x05, 0x57, 0xaf, 0x03, 0xa3, 0x66, 0x3d, 0xbc, 0xbd, 0x73,
|
||||||
0xf1, 0xf1, 0x6a, 0x39, 0x0f, 0xbd, 0xad, 0x91, 0x77, 0x7d, 0xe3, 0xef, 0xd4, 0x38, 0x4e, 0x8a,
|
0x4f, 0x4b, 0x30, 0xe7, 0xd7, 0x5c, 0xbc, 0xe7, 0x8a, 0x0f, 0xf0, 0xa8, 0x37, 0x1b, 0x0d, 0x0d,
|
||||||
0xbc, 0xbe, 0x6e, 0xa9, 0xbd, 0xde, 0x6b, 0x6f, 0x5b, 0x2c, 0x64, 0x3a, 0xda, 0xfb, 0xfc, 0x95,
|
0x70, 0xc8, 0x07, 0x09, 0x0d, 0x25, 0x25, 0x8a, 0xe3, 0x79, 0x10, 0x8c, 0x83, 0x97, 0x86, 0x76,
|
||||||
0x74, 0xbe, 0x7f, 0x23, 0xcd, 0xd7, 0x9c, 0xe0, 0xdb, 0x7b, 0xd2, 0xf9, 0x75, 0x4f, 0x3a, 0x9f,
|
0xc8, 0x71, 0xc6, 0x39, 0xe3, 0x91, 0xe2, 0xd3, 0xd9, 0xd5, 0x64, 0x32, 0x1a, 0x1a, 0x47, 0x87,
|
||||||
0x4a, 0x02, 0x6e, 0x4b, 0x02, 0x7e, 0x94, 0x04, 0xfc, 0x2e, 0x09, 0xb8, 0x70, 0xab, 0x7f, 0xe3,
|
0x7c, 0x2a, 0x45, 0x1c, 0x53, 0x82, 0x9e, 0x40, 0x7d, 0xd2, 0x9b, 0x4f, 0x47, 0x43, 0xe3, 0xd8,
|
||||||
0xe8, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x46, 0x63, 0xaf, 0x84, 0x02, 0x00, 0x00,
|
0x32, 0x6e, 0xef, 0xdc, 0x93, 0x12, 0x4f, 0xc2, 0x2c, 0x2d, 0xdb, 0x15, 0x55, 0xed, 0xf5, 0xc3,
|
||||||
|
0xdb, 0x0a, 0x33, 0x1e, 0x59, 0x67, 0x9f, 0xbf, 0xda, 0xb5, 0xef, 0xdf, 0xec, 0xea, 0x35, 0x7d,
|
||||||
|
0x73, 0x73, 0x6f, 0xd7, 0x7e, 0xdd, 0xdb, 0xb5, 0x4f, 0xb9, 0x0d, 0x36, 0xb9, 0x0d, 0x7e, 0xe4,
|
||||||
|
0x36, 0xf8, 0x93, 0xdb, 0x60, 0xa9, 0x17, 0xab, 0xb9, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x14,
|
||||||
|
0xf3, 0xee, 0x85, 0xe8, 0x02, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ syntax = "proto3";
|
||||||
package containerd.v1.types;
|
package containerd.v1.types;
|
||||||
|
|
||||||
import "gogoproto/gogo.proto";
|
import "gogoproto/gogo.proto";
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
option (gogoproto.goproto_enum_prefix) = false;
|
option (gogoproto.goproto_enum_prefix) = false;
|
||||||
|
@ -26,4 +27,5 @@ message Process {
|
||||||
string stderr = 7;
|
string stderr = 7;
|
||||||
bool terminal = 8;
|
bool terminal = 8;
|
||||||
uint32 exit_status = 9;
|
uint32 exit_status = 9;
|
||||||
|
google.protobuf.Timestamp exited_at = 10 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package containerd
|
|
||||||
|
|
||||||
import specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
||||||
|
|
||||||
// WithApparmor sets the provided apparmor profile to the spec
|
|
||||||
func WithApparmorProfile(profile string) SpecOpts {
|
|
||||||
return func(s *specs.Spec) error {
|
|
||||||
s.Process.ApparmorProfile = profile
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -123,7 +123,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
|
||||||
|
|
||||||
func getxattr(path, attr string) ([]byte, error) {
|
func getxattr(path, attr string) ([]byte, error) {
|
||||||
b, err := sysx.LGetxattr(path, attr)
|
b, err := sysx.LGetxattr(path, attr)
|
||||||
if err == unix.ENOTSUP || err == unix.ENODATA {
|
if err == unix.ENOTSUP || err == sysx.ENODATA {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
|
|
|
@ -192,6 +192,7 @@ func defaultRemoteContext() *RemoteContext {
|
||||||
Resolver: docker.NewResolver(docker.ResolverOptions{
|
Resolver: docker.NewResolver(docker.ResolverOptions{
|
||||||
Client: http.DefaultClient,
|
Client: http.DefaultClient,
|
||||||
}),
|
}),
|
||||||
|
Snapshotter: DefaultSnapshotter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +353,52 @@ func (c *Client) ListImages(ctx context.Context) ([]Image, error) {
|
||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subscribe to events that match one or more of the provided filters.
|
||||||
|
//
|
||||||
|
// Callers should listen on both the envelope channel and errs channel. If the
|
||||||
|
// errs channel returns nil or an error, the subscriber should terminate.
|
||||||
|
//
|
||||||
|
// To cancel shutdown reciept of events, cancel the provided context. The errs
|
||||||
|
// channel will be closed and return a nil error.
|
||||||
|
func (c *Client) Subscribe(ctx context.Context, filters ...string) (ch <-chan *eventsapi.Envelope, errs <-chan error) {
|
||||||
|
var (
|
||||||
|
evq = make(chan *eventsapi.Envelope)
|
||||||
|
errq = make(chan error, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = errq
|
||||||
|
ch = evq
|
||||||
|
|
||||||
|
session, err := c.EventService().Subscribe(ctx, &eventsapi.SubscribeRequest{
|
||||||
|
Filters: filters,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
errq <- err
|
||||||
|
close(errq)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(errq)
|
||||||
|
|
||||||
|
for {
|
||||||
|
ev, err := session.Recv()
|
||||||
|
if err != nil {
|
||||||
|
errq <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case evq <- ev:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch, errs
|
||||||
|
}
|
||||||
|
|
||||||
// Close closes the clients connection to containerd
|
// Close closes the clients connection to containerd
|
||||||
func (c *Client) Close() error {
|
func (c *Client) Close() error {
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
|
|
|
@ -173,9 +173,13 @@ func (c *container) NewTask(ctx context.Context, ioCreate IOCreation, opts ...Ne
|
||||||
Stdout: cfg.Stdout,
|
Stdout: cfg.Stdout,
|
||||||
Stderr: cfg.Stderr,
|
Stderr: cfg.Stderr,
|
||||||
}
|
}
|
||||||
if c.c.RootFS != "" {
|
if c.c.SnapshotKey != "" {
|
||||||
|
if c.c.Snapshotter == "" {
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "unable to resolve rootfs mounts without snapshotter on container")
|
||||||
|
}
|
||||||
|
|
||||||
// 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(c.c.Snapshotter).Mounts(ctx, c.c.RootFS)
|
mounts, err := c.client.SnapshotService(c.c.Snapshotter).Mounts(ctx, c.c.SnapshotKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -241,19 +245,7 @@ func (c *container) loadTask(ctx context.Context, ioAttach IOAttach) (Task, erro
|
||||||
}
|
}
|
||||||
var i IO
|
var i IO
|
||||||
if ioAttach != nil {
|
if ioAttach != nil {
|
||||||
// get the existing fifo paths from the task information stored by the daemon
|
if i, err = attachExistingIO(response, ioAttach); err != nil {
|
||||||
paths := &FIFOSet{
|
|
||||||
Dir: getFifoDir([]string{
|
|
||||||
response.Process.Stdin,
|
|
||||||
response.Process.Stdout,
|
|
||||||
response.Process.Stderr,
|
|
||||||
}),
|
|
||||||
In: response.Process.Stdin,
|
|
||||||
Out: response.Process.Stdout,
|
|
||||||
Err: response.Process.Stderr,
|
|
||||||
Terminal: response.Process.Terminal,
|
|
||||||
}
|
|
||||||
if i, err = ioAttach(paths); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,6 +258,22 @@ func (c *container) loadTask(ctx context.Context, ioAttach IOAttach) (Task, erro
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func attachExistingIO(response *tasks.GetResponse, ioAttach IOAttach) (IO, error) {
|
||||||
|
// get the existing fifo paths from the task information stored by the daemon
|
||||||
|
paths := &FIFOSet{
|
||||||
|
Dir: getFifoDir([]string{
|
||||||
|
response.Process.Stdin,
|
||||||
|
response.Process.Stdout,
|
||||||
|
response.Process.Stderr,
|
||||||
|
}),
|
||||||
|
In: response.Process.Stdin,
|
||||||
|
Out: response.Process.Stdout,
|
||||||
|
Err: response.Process.Stderr,
|
||||||
|
Terminal: response.Process.Terminal,
|
||||||
|
}
|
||||||
|
return ioAttach(paths)
|
||||||
|
}
|
||||||
|
|
||||||
// getFifoDir looks for any non-empty path for a stdio fifo
|
// getFifoDir looks for any non-empty path for a stdio fifo
|
||||||
// and returns the dir for where it is located
|
// and returns the dir for where it is located
|
||||||
func getFifoDir(paths []string) string {
|
func getFifoDir(paths []string) string {
|
||||||
|
|
|
@ -4,7 +4,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
|
"github.com/containerd/containerd/typeurl"
|
||||||
|
"github.com/gogo/protobuf/types"
|
||||||
"github.com/opencontainers/image-spec/identity"
|
"github.com/opencontainers/image-spec/identity"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewContainerOpts allows the caller to set additional options when creating a container
|
// NewContainerOpts allows the caller to set additional options when creating a container
|
||||||
|
@ -12,10 +17,21 @@ type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Co
|
||||||
|
|
||||||
// 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) NewContainerOpts {
|
func WithRuntime(name string, options interface{}) NewContainerOpts {
|
||||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||||
|
var (
|
||||||
|
any *types.Any
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if options != nil {
|
||||||
|
any, err = typeurl.MarshalAny(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
c.Runtime = containers.RuntimeInfo{
|
c.Runtime = containers.RuntimeInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
Options: any,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -38,6 +54,8 @@ func WithContainerLabels(labels map[string]string) NewContainerOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSnapshotter sets the provided snapshotter for use by the container
|
// WithSnapshotter sets the provided snapshotter for use by the container
|
||||||
|
//
|
||||||
|
// This option must appear before other snapshotter options to have an effect.
|
||||||
func WithSnapshotter(name string) NewContainerOpts {
|
func WithSnapshotter(name string) NewContainerOpts {
|
||||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||||
c.Snapshotter = name
|
c.Snapshotter = name
|
||||||
|
@ -48,11 +66,12 @@ 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(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 {
|
if _, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, id); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.RootFS = id
|
c.SnapshotKey = id
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,23 +80,27 @@ func WithSnapshot(id string) NewContainerOpts {
|
||||||
// root filesystem in read-write mode
|
// root filesystem in read-write mode
|
||||||
func WithNewSnapshot(id string, i Image) NewContainerOpts {
|
func WithNewSnapshot(id string, i Image) 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())
|
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
setSnapshotterIfEmpty(c)
|
||||||
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
|
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.RootFS = id
|
c.SnapshotKey = id
|
||||||
c.Image = i.Name()
|
c.Image = i.Name()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSnapshotCleanup deletes the rootfs allocated for the container
|
// WithSnapshotCleanup deletes the rootfs snapshot allocated for the container
|
||||||
func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Container) error {
|
func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Container) error {
|
||||||
if c.RootFS != "" {
|
if c.SnapshotKey != "" {
|
||||||
return client.SnapshotService(c.Snapshotter).Remove(ctx, c.RootFS)
|
if c.Snapshotter == "" {
|
||||||
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot")
|
||||||
|
}
|
||||||
|
return client.SnapshotService(c.Snapshotter).Remove(ctx, c.SnapshotKey)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -86,15 +109,22 @@ 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) NewContainerOpts {
|
func WithNewSnapshotView(id string, i Image) 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())
|
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
setSnapshotterIfEmpty(c)
|
||||||
if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
|
if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.RootFS = id
|
c.SnapshotKey = id
|
||||||
c.Image = i.Name()
|
c.Image = i.Name()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setSnapshotterIfEmpty(c *containers.Container) {
|
||||||
|
if c.Snapshotter == "" {
|
||||||
|
c.Snapshotter = DefaultSnapshotter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
"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/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
protobuf "github.com/gogo/protobuf/types"
|
protobuf "github.com/gogo/protobuf/types"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
|
@ -22,7 +23,7 @@ import (
|
||||||
// WithCheckpoint allows a container to be created from the checkpointed information
|
// WithCheckpoint allows a container to be created from the checkpointed information
|
||||||
// provided by the descriptor. The image, snapshot, and runtime specifications are
|
// provided by the descriptor. The image, snapshot, and runtime specifications are
|
||||||
// restored on the container
|
// restored on the container
|
||||||
func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
func WithCheckpoint(desc v1.Descriptor, snapshotKey string) NewContainerOpts {
|
||||||
// set image and rw, and spec
|
// set image and rw, and spec
|
||||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||||
id := desc.Digest
|
id := desc.Digest
|
||||||
|
@ -38,7 +39,7 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
||||||
fk := m
|
fk := m
|
||||||
rw = &fk
|
rw = &fk
|
||||||
case images.MediaTypeDockerSchema2Manifest:
|
case images.MediaTypeDockerSchema2Manifest:
|
||||||
config, err := images.Config(ctx, store, m)
|
config, err := images.Config(ctx, store, m, platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -46,7 +47,8 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, rootfsID, identity.ChainID(diffIDs).String()); err != nil {
|
setSnapshotterIfEmpty(c)
|
||||||
|
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, snapshotKey, identity.ChainID(diffIDs).String()); err != nil {
|
||||||
if !errdefs.IsAlreadyExists(err) {
|
if !errdefs.IsAlreadyExists(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -66,7 +68,7 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
||||||
}
|
}
|
||||||
if rw != nil {
|
if rw != nil {
|
||||||
// apply the rw snapshot to the new rw layer
|
// apply the rw snapshot to the new rw layer
|
||||||
mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, rootfsID)
|
mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, snapshotKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -74,7 +76,7 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.RootFS = rootfsID
|
c.SnapshotKey = snapshotKey
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,14 +12,50 @@ import (
|
||||||
//
|
//
|
||||||
// The resources specified in this object are used to create tasks from the container.
|
// The resources specified in this object are used to create tasks from the container.
|
||||||
type Container struct {
|
type Container struct {
|
||||||
|
// ID uniquely identifies the container in a nameapace.
|
||||||
|
//
|
||||||
|
// This property is required and cannot be changed after creation.
|
||||||
ID string
|
ID string
|
||||||
|
|
||||||
|
// Labels provide metadata extension for a contaienr.
|
||||||
|
//
|
||||||
|
// These are optional and fully mutable.
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
|
|
||||||
|
// Image specifies the image reference used for a container.
|
||||||
|
//
|
||||||
|
// This property is optional but immutable.
|
||||||
Image string
|
Image string
|
||||||
|
|
||||||
|
// Runtime specifies which runtime should be used when launching container
|
||||||
|
// tasks.
|
||||||
|
//
|
||||||
|
// This property is required and immutable.
|
||||||
Runtime RuntimeInfo
|
Runtime RuntimeInfo
|
||||||
|
|
||||||
|
// Spec should carry the the runtime specification used to implement the
|
||||||
|
// container.
|
||||||
|
//
|
||||||
|
// This field is required but mutable.
|
||||||
Spec *types.Any
|
Spec *types.Any
|
||||||
RootFS string
|
|
||||||
|
// SnapshotKey specifies the snapshot key to use for the container's root
|
||||||
|
// filesystem. When starting a task from this container, a caller should
|
||||||
|
// look up the mounts from the snapshot service and include those on the
|
||||||
|
// task create request.
|
||||||
|
//
|
||||||
|
// This field is not required but immutable.
|
||||||
|
SnapshotKey string
|
||||||
|
|
||||||
|
// Snapshotter specifies the snapshotter name used for rootfs
|
||||||
|
//
|
||||||
|
// This field is not required but immutable.
|
||||||
Snapshotter string
|
Snapshotter string
|
||||||
|
|
||||||
|
// CreatedAt is the time at which the container was created.
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
|
|
||||||
|
// UpdatedAt is the time at which the container was updated.
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +70,7 @@ type Store interface {
|
||||||
// List returns containers that match one or more of the provided filters.
|
// List returns containers that match one or more of the provided filters.
|
||||||
List(ctx context.Context, filters ...string) ([]Container, error)
|
List(ctx context.Context, filters ...string) ([]Container, error)
|
||||||
|
|
||||||
|
// Create a container in the store from the provided container.
|
||||||
Create(ctx context.Context, container Container) (Container, error)
|
Create(ctx context.Context, container Container) (Container, error)
|
||||||
|
|
||||||
// Update the container with the provided container object. ID must be set.
|
// Update the container with the provided container object. ID must be set.
|
||||||
|
@ -42,5 +79,9 @@ type Store interface {
|
||||||
// the fieldpaths will be mutated.
|
// the fieldpaths will be mutated.
|
||||||
Update(ctx context.Context, container Container, fieldpaths ...string) (Container, error)
|
Update(ctx context.Context, container Container, fieldpaths ...string) (Container, error)
|
||||||
|
|
||||||
|
// Delete a container using the id.
|
||||||
|
//
|
||||||
|
// nil will be returned on success. If the container is not known to the
|
||||||
|
// store, ErrNotFound will be returned.
|
||||||
Delete(ctx context.Context, id string) error
|
Delete(ctx context.Context, id string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ func containerToProto(container *containers.Container) containersapi.Container {
|
||||||
},
|
},
|
||||||
Spec: container.Spec,
|
Spec: container.Spec,
|
||||||
Snapshotter: container.Snapshotter,
|
Snapshotter: container.Snapshotter,
|
||||||
RootFS: container.RootFS,
|
SnapshotKey: container.SnapshotKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ func containerFromProto(containerpb *containersapi.Container) containers.Contain
|
||||||
Runtime: runtime,
|
Runtime: runtime,
|
||||||
Spec: containerpb.Spec,
|
Spec: containerpb.Spec,
|
||||||
Snapshotter: containerpb.Snapshotter,
|
Snapshotter: containerpb.Snapshotter,
|
||||||
RootFS: containerpb.RootFS,
|
SnapshotKey: containerpb.SnapshotKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ type Writer interface {
|
||||||
|
|
||||||
// Commit commits the blob (but no roll-back is guaranteed on an error).
|
// Commit commits the blob (but no roll-back is guaranteed on an error).
|
||||||
// size and expected can be zero-value when unknown.
|
// size and expected can be zero-value when unknown.
|
||||||
Commit(size int64, expected digest.Digest, opts ...Opt) error
|
Commit(ctx context.Context, size int64, expected digest.Digest, opts ...Opt) error
|
||||||
|
|
||||||
// Status returns the current state of write
|
// Status returns the current state of write
|
||||||
Status() (Status, error)
|
Status() (Status, error)
|
||||||
|
|
|
@ -58,7 +58,7 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i
|
||||||
}
|
}
|
||||||
defer cw.Close()
|
defer cw.Close()
|
||||||
|
|
||||||
return Copy(cw, r, size, expected)
|
return Copy(ctx, cw, r, size, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy copies data with the expected digest from the reader into the
|
// Copy copies data with the expected digest from the reader into the
|
||||||
|
@ -68,7 +68,7 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i
|
||||||
// the size or digest is unknown, these values may be empty.
|
// the size or digest is unknown, these values may be empty.
|
||||||
//
|
//
|
||||||
// Copy is buffered, so no need to wrap reader in buffered io.
|
// Copy is buffered, so no need to wrap reader in buffered io.
|
||||||
func Copy(cw Writer, r io.Reader, size int64, expected digest.Digest) error {
|
func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected digest.Digest) error {
|
||||||
ws, err := cw.Status()
|
ws, err := cw.Status()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -95,7 +95,7 @@ func Copy(cw Writer, r io.Reader, size int64, expected digest.Digest) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cw.Commit(size, expected); err != nil {
|
if err := cw.Commit(ctx, size, expected); err != nil {
|
||||||
if !errdefs.IsAlreadyExists(err) {
|
if !errdefs.IsAlreadyExists(err) {
|
||||||
return errors.Wrapf(err, "failed commit on ref %q", ws.Ref)
|
return errors.Wrapf(err, "failed commit on ref %q", ws.Ref)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -54,7 +55,11 @@ func (w *writer) Write(p []byte) (n int, err error) {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *writer) Commit(size int64, expected digest.Digest, opts ...content.Opt) error {
|
func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
|
||||||
|
if w.fp == nil {
|
||||||
|
return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot commit on closed writer")
|
||||||
|
}
|
||||||
|
|
||||||
if err := w.fp.Sync(); err != nil {
|
if err := w.fp.Sync(); err != nil {
|
||||||
return errors.Wrap(err, "sync failed")
|
return errors.Wrap(err, "sync failed")
|
||||||
}
|
}
|
||||||
|
@ -115,8 +120,8 @@ func (w *writer) Commit(size int64, expected digest.Digest, opts ...content.Opt)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock(w.ref)
|
|
||||||
w.fp = nil
|
w.fp = nil
|
||||||
|
unlock(w.ref)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -130,12 +135,13 @@ func (w *writer) Commit(size int64, expected digest.Digest, opts ...content.Opt)
|
||||||
//
|
//
|
||||||
// To abandon a transaction completely, first call close then `Store.Remove` to
|
// To abandon a transaction completely, first call close then `Store.Remove` to
|
||||||
// clean up the associated resources.
|
// clean up the associated resources.
|
||||||
func (cw *writer) Close() (err error) {
|
func (w *writer) Close() (err error) {
|
||||||
unlock(cw.ref)
|
if w.fp != nil {
|
||||||
|
w.fp.Sync()
|
||||||
if cw.fp != nil {
|
err = w.fp.Close()
|
||||||
cw.fp.Sync()
|
w.fp = nil
|
||||||
return cw.fp.Close()
|
unlock(w.ref)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -4,11 +4,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containerd/containerd/archive"
|
"github.com/containerd/containerd/archive"
|
||||||
"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/metadata"
|
"github.com/containerd/containerd/metadata"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
|
@ -21,7 +24,7 @@ import (
|
||||||
func init() {
|
func init() {
|
||||||
plugin.Register(&plugin.Registration{
|
plugin.Register(&plugin.Registration{
|
||||||
Type: plugin.DiffPlugin,
|
Type: plugin.DiffPlugin,
|
||||||
ID: "base-diff",
|
ID: "walking",
|
||||||
Requires: []plugin.PluginType{
|
Requires: []plugin.PluginType{
|
||||||
plugin.ContentPlugin,
|
plugin.ContentPlugin,
|
||||||
plugin.MetadataPlugin,
|
plugin.MetadataPlugin,
|
||||||
|
@ -35,27 +38,43 @@ func init() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewBaseDiff(metadata.NewContentStore(md.(*bolt.DB), c.(content.Store)))
|
return NewWalkingDiff(metadata.NewContentStore(md.(*bolt.DB), c.(content.Store)))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseDiff struct {
|
type walkingDiff struct {
|
||||||
store content.Store
|
store content.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ plugin.Differ = &BaseDiff{}
|
|
||||||
|
|
||||||
var emptyDesc = ocispec.Descriptor{}
|
var emptyDesc = ocispec.Descriptor{}
|
||||||
|
|
||||||
func NewBaseDiff(store content.Store) (*BaseDiff, error) {
|
// NewWalkingDiff is a generic implementation of plugin.Differ.
|
||||||
return &BaseDiff{
|
// NewWalkingDiff is expected to work with any filesystem.
|
||||||
|
func NewWalkingDiff(store content.Store) (plugin.Differ, error) {
|
||||||
|
return &walkingDiff{
|
||||||
store: store,
|
store: store,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (ocispec.Descriptor, error) {
|
// Apply applies the content associated with the provided digests onto the
|
||||||
// TODO: Check for supported media types
|
// provided mounts. Archive content will be extracted and decompressed if
|
||||||
|
// necessary.
|
||||||
|
func (s *walkingDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (ocispec.Descriptor, error) {
|
||||||
|
var isCompressed bool
|
||||||
|
switch desc.MediaType {
|
||||||
|
case ocispec.MediaTypeImageLayer, images.MediaTypeDockerSchema2Layer:
|
||||||
|
case ocispec.MediaTypeImageLayerGzip, images.MediaTypeDockerSchema2LayerGzip:
|
||||||
|
isCompressed = true
|
||||||
|
default:
|
||||||
|
// Still apply all generic media types *.tar[.+]gzip and *.tar
|
||||||
|
if strings.HasSuffix(desc.MediaType, ".tar.gzip") || strings.HasSuffix(desc.MediaType, ".tar+gzip") {
|
||||||
|
isCompressed = true
|
||||||
|
} else if !strings.HasSuffix(desc.MediaType, ".tar") {
|
||||||
|
return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "extract-")
|
dir, err := ioutil.TempDir("", "extract-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyDesc, errors.Wrap(err, "failed to create temporary directory")
|
return emptyDesc, errors.Wrap(err, "failed to create temporary directory")
|
||||||
|
@ -67,22 +86,25 @@ func (s *BaseDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []
|
||||||
}
|
}
|
||||||
defer mount.Unmount(dir, 0)
|
defer mount.Unmount(dir, 0)
|
||||||
|
|
||||||
r, err := s.store.ReaderAt(ctx, desc.Digest)
|
ra, err := s.store.ReaderAt(ctx, desc.Digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
|
return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer ra.Close()
|
||||||
|
|
||||||
// TODO: only decompress stream if media type is compressed
|
r := content.NewReader(ra)
|
||||||
ds, err := compression.DecompressStream(content.NewReader(r))
|
if isCompressed {
|
||||||
|
ds, err := compression.DecompressStream(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyDesc, err
|
return emptyDesc, err
|
||||||
}
|
}
|
||||||
defer ds.Close()
|
defer ds.Close()
|
||||||
|
r = ds
|
||||||
|
}
|
||||||
|
|
||||||
digester := digest.Canonical.Digester()
|
digester := digest.Canonical.Digester()
|
||||||
rc := &readCounter{
|
rc := &readCounter{
|
||||||
r: io.TeeReader(ds, digester.Hash()),
|
r: io.TeeReader(r, digester.Hash()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := archive.Apply(ctx, dir, rc); err != nil {
|
if _, err := archive.Apply(ctx, dir, rc); err != nil {
|
||||||
|
@ -101,7 +123,9 @@ func (s *BaseDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, media, ref string) (ocispec.Descriptor, error) {
|
// DiffMounts creates a diff between the given mounts and uploads the result
|
||||||
|
// to the content store.
|
||||||
|
func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, media, ref string) (ocispec.Descriptor, error) {
|
||||||
var isCompressed bool
|
var isCompressed bool
|
||||||
switch media {
|
switch media {
|
||||||
case ocispec.MediaTypeImageLayer:
|
case ocispec.MediaTypeImageLayer:
|
||||||
|
@ -111,7 +135,7 @@ func (s *BaseDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, m
|
||||||
media = ocispec.MediaTypeImageLayerGzip
|
media = ocispec.MediaTypeImageLayerGzip
|
||||||
isCompressed = true
|
isCompressed = true
|
||||||
default:
|
default:
|
||||||
return emptyDesc, errors.Errorf("unsupported diff media type: %v", media)
|
return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", media)
|
||||||
}
|
}
|
||||||
aDir, err := ioutil.TempDir("", "left-")
|
aDir, err := ioutil.TempDir("", "left-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -162,7 +186,7 @@ func (s *BaseDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, m
|
||||||
}
|
}
|
||||||
|
|
||||||
dgst := cw.Digest()
|
dgst := cw.Digest()
|
||||||
if err := cw.Commit(0, dgst, opts...); err != nil {
|
if err := cw.Commit(ctx, 0, dgst, opts...); err != nil {
|
||||||
return emptyDesc, errors.Wrap(err, "failed to commit")
|
return emptyDesc, errors.Wrap(err, "failed to commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ var (
|
||||||
ErrAlreadyExists = errors.New("already exists")
|
ErrAlreadyExists = errors.New("already exists")
|
||||||
ErrFailedPrecondition = errors.New("failed precondition")
|
ErrFailedPrecondition = errors.New("failed precondition")
|
||||||
ErrUnavailable = errors.New("unavailable")
|
ErrUnavailable = errors.New("unavailable")
|
||||||
|
ErrNotImplemented = errors.New("not implemented") // represents not supported and unimplemented
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsInvalidArgument(err error) bool {
|
func IsInvalidArgument(err error) bool {
|
||||||
|
@ -52,3 +53,7 @@ func IsFailedPrecondition(err error) bool {
|
||||||
func IsUnavailable(err error) bool {
|
func IsUnavailable(err error) bool {
|
||||||
return errors.Cause(err) == ErrUnavailable
|
return errors.Cause(err) == ErrUnavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNotImplemented(err error) bool {
|
||||||
|
return errors.Cause(err) == ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ func ToGRPC(err error) error {
|
||||||
return grpc.Errorf(codes.FailedPrecondition, err.Error())
|
return grpc.Errorf(codes.FailedPrecondition, err.Error())
|
||||||
case IsUnavailable(err):
|
case IsUnavailable(err):
|
||||||
return grpc.Errorf(codes.Unavailable, err.Error())
|
return grpc.Errorf(codes.Unavailable, err.Error())
|
||||||
|
case IsNotImplemented(err):
|
||||||
|
return grpc.Errorf(codes.Unimplemented, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -69,17 +71,17 @@ func FromGRPC(err error) error {
|
||||||
cls = ErrUnavailable
|
cls = ErrUnavailable
|
||||||
case codes.FailedPrecondition:
|
case codes.FailedPrecondition:
|
||||||
cls = ErrFailedPrecondition
|
cls = ErrFailedPrecondition
|
||||||
|
case codes.Unimplemented:
|
||||||
|
cls = ErrNotImplemented
|
||||||
default:
|
default:
|
||||||
cls = ErrUnknown
|
cls = ErrUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
if cls != nil {
|
|
||||||
msg := rebaseMessage(cls, err)
|
msg := rebaseMessage(cls, err)
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
err = errors.Wrapf(cls, msg)
|
err = errors.Wrapf(cls, msg)
|
||||||
} else {
|
} else {
|
||||||
err = cls
|
err = errors.WithStack(cls)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -22,3 +22,7 @@ type publisherFunc func(ctx context.Context, topic string, event Event) error
|
||||||
func (fn publisherFunc) Publish(ctx context.Context, topic string, event Event) error {
|
func (fn publisherFunc) Publish(ctx context.Context, topic string, event Event) error {
|
||||||
return fn(ctx, topic, event)
|
return fn(ctx, topic, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Subscriber interface {
|
||||||
|
Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error)
|
||||||
|
}
|
||||||
|
|
|
@ -185,11 +185,11 @@ func validateTopic(topic string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if topic[0] != '/' {
|
if topic[0] != '/' {
|
||||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "must start with '/'", topic)
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "must start with '/'")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(topic) == 1 {
|
if len(topic) == 1 {
|
||||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "must have at least one component", topic)
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "must have at least one component")
|
||||||
}
|
}
|
||||||
|
|
||||||
components := strings.Split(topic[1:], "/")
|
components := strings.Split(topic[1:], "/")
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
|
|
||||||
"github.com/containerd/continuity/sysx"
|
"github.com/containerd/continuity/sysx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// whiteouts are files with a special meaning for the layered filesystem.
|
// whiteouts are files with a special meaning for the layered filesystem.
|
||||||
|
@ -84,11 +83,11 @@ func compareSysStat(s1, s2 interface{}) (bool, error) {
|
||||||
|
|
||||||
func compareCapabilities(p1, p2 string) (bool, error) {
|
func compareCapabilities(p1, p2 string) (bool, error) {
|
||||||
c1, err := sysx.LGetxattr(p1, "security.capability")
|
c1, err := sysx.LGetxattr(p1, "security.capability")
|
||||||
if err != nil && err != unix.ENODATA {
|
if err != nil && err != sysx.ENODATA {
|
||||||
return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
|
return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
|
||||||
}
|
}
|
||||||
c2, err := sysx.LGetxattr(p2, "security.capability")
|
c2, err := sysx.LGetxattr(p2, "security.capability")
|
||||||
if err != nil && err != unix.ENODATA {
|
if err != nil && err != sysx.ENODATA {
|
||||||
return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
|
return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
|
||||||
}
|
}
|
||||||
return bytes.Equal(c1, c2), nil
|
return bytes.Equal(c1, c2), nil
|
||||||
|
|
|
@ -2,10 +2,9 @@ package containerd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/content"
|
|
||||||
"github.com/containerd/containerd/images"
|
"github.com/containerd/containerd/images"
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/containerd/containerd/rootfs"
|
"github.com/containerd/containerd/rootfs"
|
||||||
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"
|
||||||
|
@ -20,10 +19,12 @@ type Image interface {
|
||||||
Target() ocispec.Descriptor
|
Target() ocispec.Descriptor
|
||||||
// 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) error
|
||||||
// RootFS returns the image digests
|
// 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 image size
|
// Size returns the total size of the image's packed resources.
|
||||||
Size(ctx context.Context) (int64, error)
|
Size(ctx context.Context) (int64, error)
|
||||||
|
// Config descriptor for the image.
|
||||||
|
Config(ctx context.Context) (ocispec.Descriptor, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = (Image)(&image{})
|
var _ = (Image)(&image{})
|
||||||
|
@ -44,7 +45,7 @@ func (i *image) Target() ocispec.Descriptor {
|
||||||
|
|
||||||
func (i *image) RootFS(ctx context.Context) ([]digest.Digest, error) {
|
func (i *image) RootFS(ctx context.Context) ([]digest.Digest, error) {
|
||||||
provider := i.client.ContentStore()
|
provider := i.client.ContentStore()
|
||||||
return i.i.RootFS(ctx, provider)
|
return i.i.RootFS(ctx, provider, platforms.Format(platforms.Default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *image) Size(ctx context.Context) (int64, error) {
|
func (i *image) Size(ctx context.Context) (int64, error) {
|
||||||
|
@ -52,8 +53,13 @@ func (i *image) Size(ctx context.Context) (int64, error) {
|
||||||
return i.i.Size(ctx, provider)
|
return i.i.Size(ctx, provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) {
|
||||||
|
provider := i.client.ContentStore()
|
||||||
|
return i.i.Config(ctx, provider, platforms.Format(platforms.Default()))
|
||||||
|
}
|
||||||
|
|
||||||
func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
|
func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
|
||||||
layers, err := i.getLayers(ctx)
|
layers, err := i.getLayers(ctx, platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -91,19 +97,15 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *image) getLayers(ctx context.Context) ([]rootfs.Layer, error) {
|
func (i *image) getLayers(ctx context.Context, platform string) ([]rootfs.Layer, error) {
|
||||||
cs := i.client.ContentStore()
|
cs := i.client.ContentStore()
|
||||||
|
|
||||||
// TODO: Support manifest list
|
manifest, err := images.Manifest(ctx, cs, i.i.Target, platform)
|
||||||
p, err := content.ReadBlob(ctx, cs, i.i.Target.Digest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to read manifest blob")
|
return nil, errors.Wrap(err, "")
|
||||||
}
|
}
|
||||||
var manifest ocispec.Manifest
|
|
||||||
if err := json.Unmarshal(p, &manifest); err != nil {
|
diffIDs, err := i.i.RootFS(ctx, cs, platform)
|
||||||
return nil, errors.Wrap(err, "failed to unmarshal manifest")
|
|
||||||
}
|
|
||||||
diffIDs, err := i.i.RootFS(ctx, cs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to resolve rootfs")
|
return nil, errors.Wrap(err, "failed to resolve rootfs")
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) err
|
||||||
children, err := handler.Handle(ctx, desc)
|
children, err := handler.Handle(ctx, desc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) == SkipDesc {
|
if errors.Cause(err) == SkipDesc {
|
||||||
return nil // don't traverse the children.
|
continue // don't traverse the children.
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
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"
|
||||||
|
@ -39,16 +41,16 @@ type Store interface {
|
||||||
//
|
//
|
||||||
// The caller can then use the descriptor to resolve and process the
|
// The caller can then use the descriptor to resolve and process the
|
||||||
// configuration of the image.
|
// configuration of the image.
|
||||||
func (image *Image) Config(ctx context.Context, provider content.Provider) (ocispec.Descriptor, error) {
|
func (image *Image) Config(ctx context.Context, provider content.Provider, platform string) (ocispec.Descriptor, error) {
|
||||||
return Config(ctx, provider, image.Target)
|
return Config(ctx, provider, image.Target, platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootFS returns the unpacked diffids that make up and images rootfs.
|
// RootFS returns the unpacked diffids that make up and images rootfs.
|
||||||
//
|
//
|
||||||
// These are used to verify that a set of layers unpacked to the expected
|
// These are used to verify that a set of layers unpacked to the expected
|
||||||
// values.
|
// values.
|
||||||
func (image *Image) RootFS(ctx context.Context, provider content.Provider) ([]digest.Digest, error) {
|
func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform string) ([]digest.Digest, error) {
|
||||||
desc, err := image.Config(ctx, provider)
|
desc, err := image.Config(ctx, provider, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -67,17 +69,23 @@ func (image *Image) Size(ctx context.Context, provider content.Provider) (int64,
|
||||||
}), ChildrenHandler(provider)), image.Target)
|
}), ChildrenHandler(provider)), image.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config resolves the image configuration descriptor using a content provided
|
func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Manifest, error) {
|
||||||
// to resolve child resources on the image.
|
var (
|
||||||
//
|
matcher platforms.Matcher
|
||||||
// The caller can then use the descriptor to resolve and process the
|
m *ocispec.Manifest
|
||||||
// configuration of the image.
|
err error
|
||||||
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor) (ocispec.Descriptor, error) {
|
)
|
||||||
var configDesc ocispec.Descriptor
|
if platform != "" {
|
||||||
return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
matcher, err = platforms.Parse(platform)
|
||||||
switch image.MediaType {
|
if err != nil {
|
||||||
|
return ocispec.Manifest{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||||
|
switch desc.MediaType {
|
||||||
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
||||||
p, err := content.ReadBlob(ctx, provider, image.Digest)
|
p, err := content.ReadBlob(ctx, provider, desc.Digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -87,14 +95,108 @@ func Config(ctx context.Context, provider content.Provider, image ocispec.Descri
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
configDesc = manifest.Config
|
if platform != "" {
|
||||||
|
if desc.Platform != nil && !matcher.Match(*desc.Platform) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
default:
|
|
||||||
return nil, errors.New("could not resolve config")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}), image)
|
if desc.Platform == nil {
|
||||||
|
p, err := content.ReadBlob(ctx, provider, manifest.Config.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var image ocispec.Image
|
||||||
|
if err := json.Unmarshal(p, &image); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matcher.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m = &manifest
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
||||||
|
p, err := content.ReadBlob(ctx, provider, desc.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var idx ocispec.Index
|
||||||
|
if err := json.Unmarshal(p, &idx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if platform == "" {
|
||||||
|
return idx.Manifests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var descs []ocispec.Descriptor
|
||||||
|
for _, d := range idx.Manifests {
|
||||||
|
if d.Platform == nil || matcher.Match(*d.Platform) {
|
||||||
|
descs = append(descs, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return descs, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil, errors.New("could not resolve manifest")
|
||||||
|
}), image); err != nil {
|
||||||
|
return ocispec.Manifest{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m == nil {
|
||||||
|
return ocispec.Manifest{}, errors.Wrap(errdefs.ErrNotFound, "manifest not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return *m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config resolves the image configuration descriptor using a content provided
|
||||||
|
// to resolve child resources on the image.
|
||||||
|
//
|
||||||
|
// The caller can then use the descriptor to resolve and process the
|
||||||
|
// configuration of the image.
|
||||||
|
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Descriptor, error) {
|
||||||
|
manifest, err := Manifest(ctx, provider, image, platform)
|
||||||
|
if err != nil {
|
||||||
|
return ocispec.Descriptor{}, err
|
||||||
|
}
|
||||||
|
return manifest.Config, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platforms returns one or more platforms supported by the image.
|
||||||
|
func Platforms(ctx context.Context, provider content.Provider, image ocispec.Descriptor) ([]ocispec.Platform, error) {
|
||||||
|
var platformSpecs []ocispec.Platform
|
||||||
|
return platformSpecs, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||||
|
if desc.Platform != nil {
|
||||||
|
platformSpecs = append(platformSpecs, *desc.Platform)
|
||||||
|
return nil, SkipDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
switch desc.MediaType {
|
||||||
|
case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
|
||||||
|
p, err := content.ReadBlob(ctx, provider, desc.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var image ocispec.Image
|
||||||
|
if err := json.Unmarshal(p, &image); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
platformSpecs = append(platformSpecs,
|
||||||
|
platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture}))
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}), ChildrenHandler(provider)), image)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootFS returns the unpacked diffids that make up and images rootfs.
|
// RootFS returns the unpacked diffids that make up and images rootfs.
|
||||||
|
|
|
@ -24,7 +24,6 @@ type IOConfig struct {
|
||||||
type IO interface {
|
type IO interface {
|
||||||
// Config returns the IO configuration.
|
// Config returns the IO configuration.
|
||||||
Config() IOConfig
|
Config() IOConfig
|
||||||
|
|
||||||
// Cancel aborts all current io operations
|
// Cancel aborts all current io operations
|
||||||
Cancel()
|
Cancel()
|
||||||
// Wait blocks until all io copy operations have completed
|
// Wait blocks until all io copy operations have completed
|
||||||
|
|
|
@ -88,3 +88,85 @@ func copyIO(fifos *FIFOSet, ioset *ioSet, tty bool) (_ *wgCloser, err error) {
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDirectIO returns an IO implementation that exposes the pipes directly
|
||||||
|
func NewDirectIO(ctx context.Context, terminal bool) (*DirectIO, error) {
|
||||||
|
set, err := NewFifos("")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f := &DirectIO{
|
||||||
|
set: set,
|
||||||
|
terminal: terminal,
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
f.Delete()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if f.Stdin, err = fifo.OpenFifo(ctx, set.In, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if f.Stdout, err = fifo.OpenFifo(ctx, set.Out, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
|
||||||
|
f.Stdin.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if f.Stderr, err = fifo.OpenFifo(ctx, set.Err, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
|
||||||
|
f.Stdin.Close()
|
||||||
|
f.Stdout.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirectIO struct {
|
||||||
|
Stdin io.WriteCloser
|
||||||
|
Stdout io.ReadCloser
|
||||||
|
Stderr io.ReadCloser
|
||||||
|
|
||||||
|
set *FIFOSet
|
||||||
|
terminal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) IOCreate(id string) (IO, error) {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) IOAttach(set *FIFOSet) (IO, error) {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) Config() IOConfig {
|
||||||
|
return IOConfig{
|
||||||
|
Terminal: f.terminal,
|
||||||
|
Stdin: f.set.In,
|
||||||
|
Stdout: f.set.Out,
|
||||||
|
Stderr: f.set.Err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) Cancel() {
|
||||||
|
// nothing to cancel as all operations are handled externally
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) Wait() {
|
||||||
|
// nothing to wait on as all operations are handled externally
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) Close() error {
|
||||||
|
err := f.Stdin.Close()
|
||||||
|
if err2 := f.Stdout.Close(); err == nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
if err2 := f.Stderr.Close(); err == nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *DirectIO) Delete() error {
|
||||||
|
if f.set.Dir == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.RemoveAll(f.set.Dir)
|
||||||
|
}
|
||||||
|
|
|
@ -37,8 +37,10 @@ var _ = math.Inf
|
||||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
type RuncOptions struct {
|
type RuncOptions struct {
|
||||||
CriuPath string `protobuf:"bytes,1,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"`
|
Runtime string `protobuf:"bytes,1,opt,name=runtime,proto3" json:"runtime,omitempty"`
|
||||||
SystemdCgroup string `protobuf:"bytes,2,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"`
|
RuntimeRoot string `protobuf:"bytes,2,opt,name=runtime_root,json=runtimeRoot,proto3" json:"runtime_root,omitempty"`
|
||||||
|
CriuPath string `protobuf:"bytes,3,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"`
|
||||||
|
SystemdCgroup bool `protobuf:"varint,4,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *RuncOptions) Reset() { *m = RuncOptions{} }
|
func (m *RuncOptions) Reset() { *m = RuncOptions{} }
|
||||||
|
@ -95,17 +97,33 @@ func (m *RuncOptions) MarshalTo(dAtA []byte) (int, error) {
|
||||||
_ = i
|
_ = i
|
||||||
var l int
|
var l int
|
||||||
_ = l
|
_ = l
|
||||||
if len(m.CriuPath) > 0 {
|
if len(m.Runtime) > 0 {
|
||||||
dAtA[i] = 0xa
|
dAtA[i] = 0xa
|
||||||
i++
|
i++
|
||||||
|
i = encodeVarintRunc(dAtA, i, uint64(len(m.Runtime)))
|
||||||
|
i += copy(dAtA[i:], m.Runtime)
|
||||||
|
}
|
||||||
|
if len(m.RuntimeRoot) > 0 {
|
||||||
|
dAtA[i] = 0x12
|
||||||
|
i++
|
||||||
|
i = encodeVarintRunc(dAtA, i, uint64(len(m.RuntimeRoot)))
|
||||||
|
i += copy(dAtA[i:], m.RuntimeRoot)
|
||||||
|
}
|
||||||
|
if len(m.CriuPath) > 0 {
|
||||||
|
dAtA[i] = 0x1a
|
||||||
|
i++
|
||||||
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuPath)))
|
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuPath)))
|
||||||
i += copy(dAtA[i:], m.CriuPath)
|
i += copy(dAtA[i:], m.CriuPath)
|
||||||
}
|
}
|
||||||
if len(m.SystemdCgroup) > 0 {
|
if m.SystemdCgroup {
|
||||||
dAtA[i] = 0x12
|
dAtA[i] = 0x20
|
||||||
|
i++
|
||||||
|
if m.SystemdCgroup {
|
||||||
|
dAtA[i] = 1
|
||||||
|
} else {
|
||||||
|
dAtA[i] = 0
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
i = encodeVarintRunc(dAtA, i, uint64(len(m.SystemdCgroup)))
|
|
||||||
i += copy(dAtA[i:], m.SystemdCgroup)
|
|
||||||
}
|
}
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
@ -334,13 +352,20 @@ func encodeVarintRunc(dAtA []byte, offset int, v uint64) int {
|
||||||
func (m *RuncOptions) Size() (n int) {
|
func (m *RuncOptions) Size() (n int) {
|
||||||
var l int
|
var l int
|
||||||
_ = l
|
_ = l
|
||||||
|
l = len(m.Runtime)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovRunc(uint64(l))
|
||||||
|
}
|
||||||
|
l = len(m.RuntimeRoot)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovRunc(uint64(l))
|
||||||
|
}
|
||||||
l = len(m.CriuPath)
|
l = len(m.CriuPath)
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
n += 1 + l + sovRunc(uint64(l))
|
n += 1 + l + sovRunc(uint64(l))
|
||||||
}
|
}
|
||||||
l = len(m.SystemdCgroup)
|
if m.SystemdCgroup {
|
||||||
if l > 0 {
|
n += 2
|
||||||
n += 1 + l + sovRunc(uint64(l))
|
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
@ -432,6 +457,8 @@ func (this *RuncOptions) String() string {
|
||||||
return "nil"
|
return "nil"
|
||||||
}
|
}
|
||||||
s := strings.Join([]string{`&RuncOptions{`,
|
s := strings.Join([]string{`&RuncOptions{`,
|
||||||
|
`Runtime:` + fmt.Sprintf("%v", this.Runtime) + `,`,
|
||||||
|
`RuntimeRoot:` + fmt.Sprintf("%v", this.RuntimeRoot) + `,`,
|
||||||
`CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`,
|
`CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`,
|
||||||
`SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`,
|
`SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`,
|
||||||
`}`,
|
`}`,
|
||||||
|
@ -510,6 +537,64 @@ func (m *RuncOptions) Unmarshal(dAtA []byte) error {
|
||||||
}
|
}
|
||||||
switch fieldNum {
|
switch fieldNum {
|
||||||
case 1:
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Runtime", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowRunc
|
||||||
|
}
|
||||||
|
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 ErrInvalidLengthRunc
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Runtime = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 2:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field RuntimeRoot", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowRunc
|
||||||
|
}
|
||||||
|
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 ErrInvalidLengthRunc
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.RuntimeRoot = string(dAtA[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 3:
|
||||||
if wireType != 2 {
|
if wireType != 2 {
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field CriuPath", wireType)
|
return fmt.Errorf("proto: wrong wireType = %d for field CriuPath", wireType)
|
||||||
}
|
}
|
||||||
|
@ -538,11 +623,11 @@ func (m *RuncOptions) Unmarshal(dAtA []byte) error {
|
||||||
}
|
}
|
||||||
m.CriuPath = string(dAtA[iNdEx:postIndex])
|
m.CriuPath = string(dAtA[iNdEx:postIndex])
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
case 2:
|
case 4:
|
||||||
if wireType != 2 {
|
if wireType != 0 {
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field SystemdCgroup", wireType)
|
return fmt.Errorf("proto: wrong wireType = %d for field SystemdCgroup", wireType)
|
||||||
}
|
}
|
||||||
var stringLen uint64
|
var v int
|
||||||
for shift := uint(0); ; shift += 7 {
|
for shift := uint(0); ; shift += 7 {
|
||||||
if shift >= 64 {
|
if shift >= 64 {
|
||||||
return ErrIntOverflowRunc
|
return ErrIntOverflowRunc
|
||||||
|
@ -552,21 +637,12 @@ func (m *RuncOptions) Unmarshal(dAtA []byte) error {
|
||||||
}
|
}
|
||||||
b := dAtA[iNdEx]
|
b := dAtA[iNdEx]
|
||||||
iNdEx++
|
iNdEx++
|
||||||
stringLen |= (uint64(b) & 0x7F) << shift
|
v |= (int(b) & 0x7F) << shift
|
||||||
if b < 0x80 {
|
if b < 0x80 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
intStringLen := int(stringLen)
|
m.SystemdCgroup = bool(v != 0)
|
||||||
if intStringLen < 0 {
|
|
||||||
return ErrInvalidLengthRunc
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + intStringLen
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.SystemdCgroup = string(dAtA[iNdEx:postIndex])
|
|
||||||
iNdEx = postIndex
|
|
||||||
default:
|
default:
|
||||||
iNdEx = preIndex
|
iNdEx = preIndex
|
||||||
skippy, err := skipRunc(dAtA[iNdEx:])
|
skippy, err := skipRunc(dAtA[iNdEx:])
|
||||||
|
@ -1163,33 +1239,35 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorRunc = []byte{
|
var fileDescriptorRunc = []byte{
|
||||||
// 438 bytes of a gzipped FileDescriptorProto
|
// 467 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0xb1, 0x6f, 0xd4, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0x41, 0x6f, 0xd3, 0x40,
|
||||||
0x18, 0xc5, 0x9b, 0xb6, 0xb4, 0x89, 0xaf, 0x57, 0xc0, 0x50, 0x29, 0x14, 0x11, 0xca, 0x09, 0xa4,
|
0x10, 0x85, 0xbb, 0x6d, 0x69, 0x9d, 0x4d, 0x53, 0x60, 0xa1, 0x92, 0x29, 0xc2, 0x84, 0x08, 0xa4,
|
||||||
0xb2, 0xdc, 0x49, 0xb0, 0x20, 0xd8, 0xb8, 0x11, 0x28, 0x25, 0xc0, 0xc2, 0x62, 0xa5, 0xbe, 0x8f,
|
0x70, 0x49, 0x24, 0xb8, 0x20, 0xb8, 0x91, 0x23, 0x50, 0x2a, 0x03, 0x17, 0x2e, 0x2b, 0x77, 0x33,
|
||||||
0xc4, 0xba, 0xe4, 0xfb, 0x2c, 0xdb, 0xa1, 0xb9, 0x8d, 0x3f, 0xaf, 0x23, 0x62, 0x62, 0xa4, 0xf9,
|
0x24, 0xab, 0xd8, 0x33, 0xab, 0xdd, 0x35, 0x75, 0x6e, 0xfc, 0x02, 0x7e, 0x57, 0x8f, 0x88, 0x13,
|
||||||
0x47, 0x40, 0x71, 0x2e, 0x85, 0x95, 0x95, 0xed, 0xf9, 0xf7, 0x9e, 0x9e, 0xa5, 0x27, 0x7d, 0xec,
|
0x47, 0x9a, 0x3f, 0x02, 0xf2, 0xda, 0x2e, 0x5c, 0xb9, 0x72, 0x7b, 0xf3, 0xbd, 0xb1, 0xe7, 0xe9,
|
||||||
0x79, 0xae, 0x5c, 0x51, 0x9f, 0x4d, 0x25, 0x55, 0x33, 0x49, 0xe8, 0x32, 0x85, 0x60, 0x16, 0x7f,
|
0x49, 0xcb, 0x9f, 0x2f, 0xb4, 0x5f, 0x96, 0x67, 0x13, 0x45, 0xc5, 0x54, 0x11, 0xfa, 0x4c, 0x23,
|
||||||
0xcb, 0x52, 0x61, 0xdd, 0xcc, 0x4c, 0x8d, 0x92, 0xb4, 0xb3, 0x5e, 0x4c, 0xb5, 0x21, 0x47, 0xfc,
|
0xd8, 0xf9, 0xdf, 0x32, 0xd7, 0x58, 0x56, 0x53, 0x5b, 0xa2, 0x22, 0xe3, 0x5d, 0x10, 0x13, 0x63,
|
||||||
0xe0, 0x4f, 0x6a, 0xea, 0x53, 0xd3, 0xce, 0x3c, 0xbc, 0x9d, 0x53, 0x4e, 0x3e, 0x31, 0xeb, 0x54,
|
0xc9, 0x93, 0x38, 0xfa, 0xb3, 0x35, 0x09, 0x5b, 0x93, 0xda, 0x3c, 0xbe, 0xbd, 0xa0, 0x05, 0x85,
|
||||||
0x1f, 0x9e, 0xbc, 0x63, 0xa3, 0xb4, 0x46, 0xf9, 0x56, 0x3b, 0x45, 0x68, 0xf9, 0x5d, 0x16, 0x49,
|
0x8d, 0x69, 0xad, 0x9a, 0xe5, 0xd1, 0x57, 0xc6, 0xfb, 0x69, 0x89, 0xea, 0xad, 0xf1, 0x9a, 0xd0,
|
||||||
0xa3, 0x6a, 0xa1, 0x33, 0x57, 0xc4, 0xc1, 0x51, 0x70, 0x1c, 0xa5, 0x61, 0x07, 0x4e, 0x33, 0x57,
|
0x89, 0x98, 0xef, 0xdb, 0x12, 0xbd, 0x2e, 0x20, 0x66, 0x43, 0x36, 0xee, 0xa5, 0xdd, 0x28, 0x1e,
|
||||||
0xf0, 0x47, 0x6c, 0xdf, 0xae, 0xac, 0x83, 0x6a, 0x21, 0x64, 0x6e, 0xa8, 0xd6, 0xf1, 0xa6, 0x4f,
|
0xf0, 0x83, 0x56, 0x4a, 0x4b, 0xe4, 0xe3, 0xed, 0x60, 0xf7, 0x5b, 0x96, 0x12, 0x79, 0x71, 0x97,
|
||||||
0x8c, 0xd7, 0x74, 0xee, 0xe1, 0xe4, 0xfb, 0x26, 0x1b, 0xcf, 0x0d, 0x64, 0x0e, 0x86, 0xd6, 0x09,
|
0xf7, 0x94, 0xd5, 0xa5, 0x34, 0x99, 0x5f, 0xc6, 0x3b, 0xc1, 0x8f, 0x6a, 0x70, 0x9a, 0xf9, 0xa5,
|
||||||
0x1b, 0x23, 0x09, 0xad, 0xbe, 0x90, 0x13, 0x86, 0xc8, 0xf9, 0xe6, 0x30, 0x1d, 0x21, 0x9d, 0x76,
|
0x78, 0xc4, 0x0f, 0xdd, 0xda, 0x79, 0x28, 0xe6, 0x52, 0x2d, 0x2c, 0x95, 0x26, 0xde, 0x1d, 0xb2,
|
||||||
0x2c, 0x25, 0x72, 0xfc, 0x0e, 0x0b, 0x49, 0x03, 0x0a, 0x27, 0xfb, 0xda, 0x30, 0xdd, 0xed, 0xde,
|
0x71, 0x94, 0x0e, 0x5a, 0x3a, 0x0b, 0x70, 0xf4, 0x7d, 0x9b, 0x0f, 0x66, 0x16, 0x32, 0x0f, 0x5d,
|
||||||
0x1f, 0xa4, 0xe6, 0x4f, 0xd8, 0x01, 0x34, 0x0e, 0x0c, 0x66, 0xa5, 0xa8, 0x51, 0x35, 0xc2, 0x92,
|
0xa4, 0x11, 0x1f, 0x20, 0x49, 0xa3, 0x3f, 0x93, 0x6f, 0x2e, 0xb3, 0xf0, 0x5d, 0x1f, 0xe9, 0xb4,
|
||||||
0x5c, 0x82, 0xb3, 0xf1, 0x96, 0xcf, 0xdd, 0x1a, 0xcc, 0x8f, 0xa8, 0x9a, 0xf7, 0xbd, 0xc5, 0x0f,
|
0x66, 0xe1, 0xf2, 0x1d, 0x1e, 0x91, 0x01, 0x94, 0x5e, 0x99, 0x10, 0x2c, 0x4a, 0xf7, 0xeb, 0xf9,
|
||||||
0x59, 0xe8, 0xc0, 0x54, 0x0a, 0xb3, 0x32, 0xde, 0xf6, 0xb1, 0xab, 0x37, 0xbf, 0xc7, 0xd8, 0x67,
|
0xbd, 0x32, 0xe2, 0x09, 0x3f, 0x82, 0xca, 0x83, 0xc5, 0x2c, 0x97, 0x25, 0xea, 0x4a, 0x3a, 0x52,
|
||||||
0x55, 0x82, 0x28, 0x49, 0x2e, 0x6d, 0x7c, 0xcd, 0xbb, 0x51, 0x47, 0x5e, 0x77, 0x80, 0x3f, 0x66,
|
0x2b, 0xf0, 0x2e, 0x04, 0x8c, 0xd2, 0x5b, 0x9d, 0xf9, 0x01, 0x75, 0xf5, 0xae, 0xb1, 0xc4, 0x31,
|
||||||
0x37, 0xa0, 0xd2, 0x6e, 0x25, 0x30, 0xab, 0xc0, 0xea, 0x4c, 0x82, 0x8d, 0x77, 0x8e, 0xb6, 0x8e,
|
0x8f, 0x3c, 0xd8, 0x42, 0x63, 0x96, 0xb7, 0x29, 0xaf, 0x66, 0x71, 0x8f, 0xf3, 0x4f, 0x3a, 0x07,
|
||||||
0xa3, 0xf4, 0xba, 0xe7, 0x27, 0x57, 0x98, 0x3f, 0x60, 0x7b, 0xfd, 0x12, 0x56, 0x54, 0xb4, 0x80,
|
0x99, 0x93, 0x5a, 0xb9, 0xf8, 0x5a, 0x70, 0x7b, 0x35, 0x79, 0x5d, 0x03, 0xf1, 0x98, 0xdf, 0x80,
|
||||||
0x78, 0xd7, 0xef, 0x31, 0x5a, 0xb3, 0x37, 0xb4, 0x00, 0xfe, 0x90, 0xed, 0x23, 0x09, 0x84, 0x73,
|
0xc2, 0xf8, 0xb5, 0xc4, 0xac, 0x00, 0x67, 0x32, 0x05, 0x2e, 0xde, 0x1b, 0xee, 0x8c, 0x7b, 0xe9,
|
||||||
0xb1, 0x84, 0x95, 0x51, 0x98, 0xc7, 0xa1, 0xff, 0x70, 0x0f, 0xe9, 0x04, 0xce, 0x5f, 0xf5, 0x8c,
|
0xf5, 0xc0, 0x4f, 0xae, 0x70, 0xdd, 0x68, 0xd3, 0x84, 0x93, 0x05, 0xcd, 0x21, 0xde, 0x6f, 0x1a,
|
||||||
0xdf, 0x67, 0x23, 0x5b, 0xa8, 0x6a, 0xd8, 0x35, 0xf2, 0x3d, 0xac, 0x43, 0xeb, 0x51, 0x7f, 0x05,
|
0x6d, 0xd9, 0x1b, 0x9a, 0x83, 0x78, 0xc8, 0x0f, 0x91, 0x24, 0xc2, 0xb9, 0x5c, 0xc1, 0xda, 0x6a,
|
||||||
0xec, 0xe6, 0xbc, 0x00, 0xb9, 0xd4, 0xa4, 0xd0, 0x0d, 0xc3, 0x72, 0xb6, 0x0d, 0x8d, 0x1a, 0xf6,
|
0x5c, 0xc4, 0x51, 0x38, 0x78, 0x80, 0x74, 0x02, 0xe7, 0xaf, 0x1a, 0x26, 0xee, 0xf3, 0xbe, 0x5b,
|
||||||
0xf4, 0xfa, 0x7f, 0x1d, 0xf2, 0x65, 0x7a, 0x71, 0x99, 0x6c, 0xfc, 0xb8, 0x4c, 0x36, 0xbe, 0xb6,
|
0xea, 0xa2, 0xeb, 0xb5, 0x17, 0xfe, 0xc3, 0x6b, 0xd4, 0x96, 0xfa, 0x8b, 0xf1, 0x9b, 0xb3, 0x25,
|
||||||
0x49, 0x70, 0xd1, 0x26, 0xc1, 0xb7, 0x36, 0x09, 0x7e, 0xb6, 0x49, 0xf0, 0xe9, 0xd9, 0x3f, 0x1e,
|
0xa8, 0x95, 0x21, 0x8d, 0xbe, 0x2b, 0x56, 0xf0, 0x5d, 0xa8, 0x74, 0xd7, 0x67, 0xd0, 0xff, 0x6b,
|
||||||
0xcb, 0x8b, 0x41, 0x9c, 0xed, 0xf8, 0x23, 0x78, 0xfa, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x00, 0x19,
|
0x91, 0x2f, 0xd3, 0x8b, 0xcb, 0x64, 0xeb, 0xc7, 0x65, 0xb2, 0xf5, 0x65, 0x93, 0xb0, 0x8b, 0x4d,
|
||||||
0xba, 0x8f, 0x6f, 0x03, 0x00, 0x00,
|
0xc2, 0xbe, 0x6d, 0x12, 0xf6, 0x73, 0x93, 0xb0, 0x8f, 0xcf, 0xfe, 0xf1, 0xa9, 0xbd, 0xe8, 0xc4,
|
||||||
|
0xd9, 0x5e, 0x78, 0x42, 0x4f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x26, 0x29, 0x60, 0xad,
|
||||||
|
0x03, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ import "gogoproto/gogo.proto";
|
||||||
option go_package = "github.com/containerd/containerd/linux/runcopts;runcopts";
|
option go_package = "github.com/containerd/containerd/linux/runcopts;runcopts";
|
||||||
|
|
||||||
message RuncOptions {
|
message RuncOptions {
|
||||||
string criu_path = 1;
|
string runtime = 1;
|
||||||
string systemd_cgroup = 2;
|
string runtime_root = 2;
|
||||||
|
string criu_path = 3;
|
||||||
|
bool systemd_cgroup = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateOptions {
|
message CreateOptions {
|
||||||
|
|
|
@ -47,7 +47,8 @@ var (
|
||||||
bucketKeyParent = []byte("parent")
|
bucketKeyParent = []byte("parent")
|
||||||
bucketKeyOptions = []byte("options")
|
bucketKeyOptions = []byte("options")
|
||||||
bucketKeySpec = []byte("spec")
|
bucketKeySpec = []byte("spec")
|
||||||
bucketKeyRootFS = []byte("rootfs")
|
bucketKeySnapshotKey = []byte("snapshotKey")
|
||||||
|
bucketKeySnapshotter = []byte("snapshotter")
|
||||||
bucketKeyTarget = []byte("target")
|
bucketKeyTarget = []byte("target")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -91,8 +91,8 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
|
||||||
return containers.Container{}, err
|
return containers.Container{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := identifiers.Validate(container.ID); err != nil {
|
if err := validateContainer(&container); err != nil {
|
||||||
return containers.Container{}, err
|
return containers.Container{}, errors.Wrap(err, "create container failed validation")
|
||||||
}
|
}
|
||||||
|
|
||||||
bkt, err := createContainersBucket(s.tx, namespace)
|
bkt, err := createContainersBucket(s.tx, namespace)
|
||||||
|
@ -144,11 +144,33 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
|
||||||
createdat := updated.CreatedAt
|
createdat := updated.CreatedAt
|
||||||
updated.ID = container.ID
|
updated.ID = container.ID
|
||||||
|
|
||||||
|
if len(fieldpaths) == 0 {
|
||||||
|
// only allow updates to these field on full replace.
|
||||||
|
fieldpaths = []string{"labels", "spec"}
|
||||||
|
|
||||||
|
// 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.Image != container.Image {
|
||||||
|
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Image field is immutable")
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated.SnapshotKey != container.SnapshotKey {
|
||||||
|
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.SnapshotKey field is immutable")
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated.Snapshotter != container.Snapshotter {
|
||||||
|
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated.Runtime.Name != container.Runtime.Name {
|
||||||
|
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// apply the field mask. If you update this code, you better follow the
|
// 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
|
// field mask rules in field_mask.proto. If you don't know what this
|
||||||
// is, do not update this code.
|
// is, do not update this code.
|
||||||
if len(fieldpaths) > 0 {
|
|
||||||
// TODO(stevvooe): Move this logic into the store itself.
|
|
||||||
for _, path := range fieldpaths {
|
for _, path := range fieldpaths {
|
||||||
if strings.HasPrefix(path, "labels.") {
|
if strings.HasPrefix(path, "labels.") {
|
||||||
if updated.Labels == nil {
|
if updated.Labels == nil {
|
||||||
|
@ -162,19 +184,15 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
|
||||||
switch path {
|
switch path {
|
||||||
case "labels":
|
case "labels":
|
||||||
updated.Labels = container.Labels
|
updated.Labels = container.Labels
|
||||||
case "image":
|
|
||||||
updated.Image = container.Image
|
|
||||||
case "spec":
|
case "spec":
|
||||||
updated.Spec = container.Spec
|
updated.Spec = container.Spec
|
||||||
case "rootfs":
|
|
||||||
updated.RootFS = container.RootFS
|
|
||||||
default:
|
default:
|
||||||
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
|
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// no field mask present, just replace everything
|
if err := validateContainer(&updated); err != nil {
|
||||||
updated = container
|
return containers.Container{}, errors.Wrap(err, "update failed validation")
|
||||||
}
|
}
|
||||||
|
|
||||||
updated.CreatedAt = createdat
|
updated.CreatedAt = createdat
|
||||||
|
@ -183,7 +201,7 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
|
||||||
return containers.Container{}, errors.Wrap(err, "failed to write container")
|
return containers.Container{}, errors.Wrap(err, "failed to write container")
|
||||||
}
|
}
|
||||||
|
|
||||||
return container, nil
|
return updated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *containerStore) Delete(ctx context.Context, id string) error {
|
func (s *containerStore) Delete(ctx context.Context, id string) error {
|
||||||
|
@ -203,6 +221,27 @@ func (s *containerStore) Delete(ctx context.Context, id string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateContainer(container *containers.Container) error {
|
||||||
|
if err := identifiers.Validate(container.ID); err != nil {
|
||||||
|
return errors.Wrapf(err, "container.ID validation error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// labels and image have no validation
|
||||||
|
if container.Runtime.Name == "" {
|
||||||
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if container.Spec == nil {
|
||||||
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Spec must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if container.SnapshotKey != "" && container.Snapshotter == "" {
|
||||||
|
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set if container.SnapshotKey is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
|
func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
|
||||||
labels, err := boltutil.ReadLabels(bkt)
|
labels, err := boltutil.ReadLabels(bkt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -245,9 +284,10 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
container.Spec = &any
|
container.Spec = &any
|
||||||
case string(bucketKeyRootFS):
|
case string(bucketKeySnapshotKey):
|
||||||
container.RootFS = string(v)
|
container.SnapshotKey = string(v)
|
||||||
|
case string(bucketKeySnapshotter):
|
||||||
|
container.Snapshotter = string(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -272,7 +312,8 @@ func writeContainer(bkt *bolt.Bucket, container *containers.Container) error {
|
||||||
|
|
||||||
for _, v := range [][2][]byte{
|
for _, v := range [][2][]byte{
|
||||||
{bucketKeyImage, []byte(container.Image)},
|
{bucketKeyImage, []byte(container.Image)},
|
||||||
{bucketKeyRootFS, []byte(container.RootFS)},
|
{bucketKeySnapshotter, []byte(container.Snapshotter)},
|
||||||
|
{bucketKeySnapshotKey, []byte(container.SnapshotKey)},
|
||||||
} {
|
} {
|
||||||
if err := bkt.Put(v[0], v[1]); err != nil {
|
if err := bkt.Put(v[0], v[1]); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -294,18 +335,13 @@ func writeContainer(bkt *bolt.Bucket, container *containers.Container) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
obkt, err := rbkt.CreateBucket(bucketKeyOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if container.Runtime.Options != nil {
|
if container.Runtime.Options != nil {
|
||||||
data, err := proto.Marshal(container.Runtime.Options)
|
data, err := proto.Marshal(container.Runtime.Options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := obkt.Put(bucketKeyOptions, data); err != nil {
|
if err := rbkt.Put(bucketKeyOptions, data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,19 +352,19 @@ type namespacedWriter struct {
|
||||||
db *bolt.DB
|
db *bolt.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *namespacedWriter) Commit(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 {
|
||||||
return nw.db.Update(func(tx *bolt.Tx) error {
|
return update(ctx, nw.db, func(tx *bolt.Tx) error {
|
||||||
bkt := getIngestBucket(tx, nw.namespace)
|
bkt := getIngestBucket(tx, nw.namespace)
|
||||||
if bkt != nil {
|
if bkt != nil {
|
||||||
if err := bkt.Delete([]byte(nw.ref)); err != nil {
|
if err := bkt.Delete([]byte(nw.ref)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nw.commit(tx, size, expected, opts...)
|
return nw.commit(ctx, tx, size, expected, opts...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Digest, opts ...content.Opt) error {
|
func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64, expected digest.Digest, opts ...content.Opt) error {
|
||||||
var base content.Info
|
var base content.Info
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if err := opt(&base); err != nil {
|
if err := opt(&base); err != nil {
|
||||||
|
@ -382,7 +382,7 @@ func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Dige
|
||||||
|
|
||||||
actual := nw.Writer.Digest()
|
actual := nw.Writer.Digest()
|
||||||
|
|
||||||
if err := nw.Writer.Commit(size, expected); err != nil {
|
if err := nw.Writer.Commit(ctx, size, expected); err != nil {
|
||||||
if !errdefs.IsAlreadyExists(err) {
|
if !errdefs.IsAlreadyExists(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -481,6 +481,9 @@ func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho
|
||||||
for _, pair := range pairs {
|
for _, pair := range pairs {
|
||||||
info, err := s.Snapshotter.Stat(ctx, pair.bkey)
|
info, err := s.Snapshotter.Stat(ctx, pair.bkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errdefs.IsNotFound(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,36 @@ import (
|
||||||
|
|
||||||
func (m *Mount) Mount(target string) error {
|
func (m *Mount) Mount(target string) error {
|
||||||
flags, data := parseMountOptions(m.Options)
|
flags, data := parseMountOptions(m.Options)
|
||||||
return unix.Mount(m.Source, target, m.Type, uintptr(flags), data)
|
|
||||||
|
// propagation types.
|
||||||
|
const ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE
|
||||||
|
|
||||||
|
// Ensure propagation type change flags aren't included in other calls.
|
||||||
|
oflags := flags &^ ptypes
|
||||||
|
|
||||||
|
// In the case of remounting with changed data (data != ""), need to call mount (moby/moby#34077).
|
||||||
|
if flags&unix.MS_REMOUNT == 0 || data != "" {
|
||||||
|
// Initial call applying all non-propagation flags for mount
|
||||||
|
// or remount with changed data
|
||||||
|
if err := unix.Mount(m.Source, target, m.Type, uintptr(oflags), data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags&ptypes != 0 {
|
||||||
|
// Change the propagation type.
|
||||||
|
const pflags = ptypes | unix.MS_REC | unix.MS_SILENT
|
||||||
|
if err := unix.Mount("", target, "", uintptr(flags&pflags), ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const broflags = unix.MS_BIND | unix.MS_RDONLY
|
||||||
|
if oflags&broflags == broflags {
|
||||||
|
// Remount the bind to apply read only.
|
||||||
|
return unix.Mount("", target, "", uintptr(oflags|unix.MS_REMOUNT), "")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Unmount(mount string, flags int) error {
|
func Unmount(mount string, flags int) error {
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package platforms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These function are generated from from https://golang.org/src/go/build/syslist.go.
|
||||||
|
//
|
||||||
|
// We use switch statements because they are slightly faster than map lookups
|
||||||
|
// and use a little less memory.
|
||||||
|
|
||||||
|
// isKnownOS returns true if we know about the operating system.
|
||||||
|
//
|
||||||
|
// The OS value should be normalized before calling this function.
|
||||||
|
func isKnownOS(os string) bool {
|
||||||
|
switch os {
|
||||||
|
case "android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isKnownArch returns true if we know about the architecture.
|
||||||
|
//
|
||||||
|
// The arch value should be normalized before being passed to this function.
|
||||||
|
func isKnownArch(arch string) bool {
|
||||||
|
switch arch {
|
||||||
|
case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "s390", "s390x", "sparc", "sparc64":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeOS(os string) string {
|
||||||
|
if os == "" {
|
||||||
|
return runtime.GOOS
|
||||||
|
}
|
||||||
|
os = strings.ToLower(os)
|
||||||
|
|
||||||
|
switch os {
|
||||||
|
case "macos":
|
||||||
|
os = "darwin"
|
||||||
|
}
|
||||||
|
return os
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeArch normalizes the architecture.
|
||||||
|
func normalizeArch(arch, variant string) (string, string) {
|
||||||
|
arch, variant = strings.ToLower(arch), strings.ToLower(variant)
|
||||||
|
switch arch {
|
||||||
|
case "i386":
|
||||||
|
arch = "386"
|
||||||
|
variant = ""
|
||||||
|
case "x86_64", "x86-64":
|
||||||
|
arch = "amd64"
|
||||||
|
variant = ""
|
||||||
|
case "aarch64":
|
||||||
|
arch = "arm64"
|
||||||
|
variant = "" // v8 is implied
|
||||||
|
case "armhf":
|
||||||
|
arch = "arm"
|
||||||
|
variant = ""
|
||||||
|
case "armel":
|
||||||
|
arch = "arm"
|
||||||
|
variant = "v6"
|
||||||
|
case "arm":
|
||||||
|
switch variant {
|
||||||
|
case "v7", "7":
|
||||||
|
variant = "v7"
|
||||||
|
case "5", "6", "8":
|
||||||
|
variant = "v" + variant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arch, variant
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package platforms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Default returns the current platform's default platform specification.
|
||||||
|
func Default() specs.Platform {
|
||||||
|
return specs.Platform{
|
||||||
|
OS: runtime.GOOS,
|
||||||
|
Architecture: runtime.GOARCH,
|
||||||
|
// TODO(stevvooe): Need to resolve GOARM for arm hosts.
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
// Package platforms provides a toolkit for normalizing, matching and
|
||||||
|
// specifying container platforms.
|
||||||
|
//
|
||||||
|
// Centered around OCI platform specifications, we define a string-based
|
||||||
|
// specifier syntax that can be used for user input. With a specifier, users
|
||||||
|
// only need to specify the parts of the platform that are relevant to their
|
||||||
|
// context, providing an operating system or architecture or both.
|
||||||
|
//
|
||||||
|
// How do I use this package?
|
||||||
|
//
|
||||||
|
// The vast majority of use cases should simply use the match function with
|
||||||
|
// user input. The first step is to parse a specifier into a matcher:
|
||||||
|
//
|
||||||
|
// m, err := Parse("linux")
|
||||||
|
// if err != nil { ... }
|
||||||
|
//
|
||||||
|
// Once you have a matcher, use it to match against the platform declared by a
|
||||||
|
// component, typically from an image or runtime. Since extracting an images
|
||||||
|
// platform is a little more involved, we'll use an example against the
|
||||||
|
// platform default:
|
||||||
|
//
|
||||||
|
// if ok := m.Match(Default()); !ok { /* doesn't match */ }
|
||||||
|
//
|
||||||
|
// This can be composed in loops for resolving runtimes or used as a filter for
|
||||||
|
// fetch and select images.
|
||||||
|
//
|
||||||
|
// More details of the specifier syntax and platform spec follow.
|
||||||
|
//
|
||||||
|
// Declaring Platform Support
|
||||||
|
//
|
||||||
|
// Components that have strict platform requirements should use the OCI
|
||||||
|
// platform specification to declare their support. Typically, this will be
|
||||||
|
// images and runtimes that should make these declaring which platform they
|
||||||
|
// support specifically. This looks roughly as follows:
|
||||||
|
//
|
||||||
|
// type Platform struct {
|
||||||
|
// Architecture string
|
||||||
|
// OS string
|
||||||
|
// Variant string
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Most images and runtimes should at least set Architecture and OS, according
|
||||||
|
// to their GOARCH and GOOS values, respectively (follow the OCI image
|
||||||
|
// specification when in doubt). ARM should set variant under certain
|
||||||
|
// discussions, which are outlined below.
|
||||||
|
//
|
||||||
|
// Platform Specifiers
|
||||||
|
//
|
||||||
|
// While the OCI platform specifications provide a tool for components to
|
||||||
|
// specify structured information, user input typically doesn't need the full
|
||||||
|
// context and much can be inferred. To solve this problem, we introduced
|
||||||
|
// "specifiers". A specifier has the format
|
||||||
|
// `<os>|<arch>|<os>/<arch>[/<variant>]`. The user can provide either the
|
||||||
|
// operating system or the architecture or both.
|
||||||
|
//
|
||||||
|
// An example of a common specifier is `linux/amd64`. If the host has a default
|
||||||
|
// of runtime that matches this, the user can simply provide the component that
|
||||||
|
// matters. For example, if a image provides amd64 and arm64 support, the
|
||||||
|
// operating system, `linux` can be inferred, so they only have to provide
|
||||||
|
// `arm64` or `amd64`. Similar behavior is implemented for operating systems,
|
||||||
|
// where the architecture may be known but a runtime may support images from
|
||||||
|
// different operating systems.
|
||||||
|
//
|
||||||
|
// Normalization
|
||||||
|
//
|
||||||
|
// Because not all users are familiar with the way the Go runtime represents
|
||||||
|
// platforms, several normalizations have been provided to make this package
|
||||||
|
// easier to user.
|
||||||
|
//
|
||||||
|
// The following are performed for architectures:
|
||||||
|
//
|
||||||
|
// Value Normalized
|
||||||
|
// aarch64 arm64
|
||||||
|
// armhf arm
|
||||||
|
// armel arm/v6
|
||||||
|
// i386 386
|
||||||
|
// x86_64 amd64
|
||||||
|
// x86-64 amd64
|
||||||
|
//
|
||||||
|
// We also normalize the operating system `macos` to `darwin`.
|
||||||
|
//
|
||||||
|
// ARM Support
|
||||||
|
//
|
||||||
|
// To qualify ARM architecture, the Variant field is used to qualify the arm
|
||||||
|
// version. The most common arm version, v7, is represented without the variant
|
||||||
|
// unless it is explicitly provided. This is treated as equivalent to armhf. A
|
||||||
|
// previous architecture, armel, will be normalized to arm/v6.
|
||||||
|
//
|
||||||
|
// While these normalizations are provided, their support on arm platforms has
|
||||||
|
// not yet been fully implemented and tested.
|
||||||
|
package platforms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Matcher matches platforms specifications, provided by an image or runtime.
|
||||||
|
type Matcher interface {
|
||||||
|
Spec() specs.Platform
|
||||||
|
Match(platform specs.Platform) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type matcher struct {
|
||||||
|
specs.Platform
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *matcher) Spec() specs.Platform {
|
||||||
|
return m.Platform
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *matcher) Match(platform specs.Platform) bool {
|
||||||
|
normalized := Normalize(platform)
|
||||||
|
return m.OS == normalized.OS &&
|
||||||
|
m.Architecture == normalized.Architecture &&
|
||||||
|
m.Variant == normalized.Variant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *matcher) String() string {
|
||||||
|
return Format(m.Platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the platform specifier syntax into a platform declaration.
|
||||||
|
//
|
||||||
|
// Platform specifiers are in the format `<os>|<arch>|<os>/<arch>[/<variant>]`.
|
||||||
|
// The minimum required information for a platform specifier is the operating
|
||||||
|
// system or architecture. If there is only a single string (no slashes), the
|
||||||
|
// value will be matched against the known set of operating systems, then fall
|
||||||
|
// back to the known set of architectures. The missing component will be
|
||||||
|
// inferred based on the local environment.
|
||||||
|
//
|
||||||
|
// Applications should opt to use `Match` over directly parsing specifiers.
|
||||||
|
func Parse(specifier string) (Matcher, error) {
|
||||||
|
if strings.Contains(specifier, "*") {
|
||||||
|
// TODO(stevvooe): need to work out exact wildcard handling
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "%q: wildcards not yet supported", specifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(specifier, "/")
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
if !specifierRe.MatchString(part) {
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "%q is an invalid component of %q: platform specifier component must match %q", part, specifier, specifierRe.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var p specs.Platform
|
||||||
|
switch len(parts) {
|
||||||
|
case 1:
|
||||||
|
// in this case, we will test that the value might be an OS, then look
|
||||||
|
// it up. If it is not known, we'll treat it as an architecture. Since
|
||||||
|
// we have very little information about the platform here, we are
|
||||||
|
// going to be a little more strict if we don't know about the argument
|
||||||
|
// value.
|
||||||
|
p.OS = normalizeOS(parts[0])
|
||||||
|
if isKnownOS(p.OS) {
|
||||||
|
// picks a default architecture
|
||||||
|
p.Architecture = runtime.GOARCH
|
||||||
|
if p.Architecture == "arm" {
|
||||||
|
// TODO(stevvooe): Resolve arm variant, if not v6 (default)
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrNotImplemented, "arm support not fully implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &matcher{p}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Architecture, p.Variant = normalizeArch(parts[0], "")
|
||||||
|
if isKnownArch(p.Architecture) {
|
||||||
|
p.OS = runtime.GOOS
|
||||||
|
return &matcher{p}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "%q: unknown operating system or architecture", specifier)
|
||||||
|
case 2:
|
||||||
|
// In this case, we treat as a regular os/arch pair. We don't care
|
||||||
|
// about whether or not we know of the platform.
|
||||||
|
p.OS = normalizeOS(parts[0])
|
||||||
|
p.Architecture, p.Variant = normalizeArch(parts[1], "")
|
||||||
|
|
||||||
|
return &matcher{p}, nil
|
||||||
|
case 3:
|
||||||
|
// we have a fully specified variant, this is rare
|
||||||
|
p.OS = normalizeOS(parts[0])
|
||||||
|
p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
|
||||||
|
|
||||||
|
return &matcher{p}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "%q: cannot parse platform specifier", specifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format returns a string specifier from the provided platform specification.
|
||||||
|
func Format(platform specs.Platform) string {
|
||||||
|
if platform.OS == "" {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
return joinNotEmpty(platform.OS, platform.Architecture, platform.Variant)
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinNotEmpty(s ...string) string {
|
||||||
|
var ss []string
|
||||||
|
for _, s := range s {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ss = append(ss, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(ss, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize validates and translate the platform to the canonical value.
|
||||||
|
//
|
||||||
|
// For example, if "Aarch64" is encountered, we change it to "arm64" or if
|
||||||
|
// "x86_64" is encountered, it becomes "amd64".
|
||||||
|
func Normalize(platform specs.Platform) specs.Platform {
|
||||||
|
platform.OS = normalizeOS(platform.OS)
|
||||||
|
platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
|
||||||
|
|
||||||
|
// these fields are deprecated, remove them
|
||||||
|
platform.OSFeatures = nil
|
||||||
|
platform.OSVersion = ""
|
||||||
|
|
||||||
|
return platform
|
||||||
|
}
|
|
@ -4,13 +4,13 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||||
"github.com/containerd/containerd/api/services/tasks/v1"
|
"github.com/containerd/containerd/api/services/tasks/v1"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/runtime"
|
"github.com/containerd/containerd/runtime"
|
||||||
"github.com/containerd/containerd/typeurl"
|
"github.com/containerd/containerd/typeurl"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,11 +21,11 @@ type Process interface {
|
||||||
// Start starts the process executing the user's defined binary
|
// Start starts the process executing the user's defined binary
|
||||||
Start(context.Context) error
|
Start(context.Context) error
|
||||||
// Delete removes the process and any resources allocated returning the exit status
|
// Delete removes the process and any resources allocated returning the exit status
|
||||||
Delete(context.Context, ...ProcessDeleteOpts) (uint32, error)
|
Delete(context.Context, ...ProcessDeleteOpts) (*ExitStatus, error)
|
||||||
// Kill sends the provided signal to the process
|
// Kill sends the provided signal to the process
|
||||||
Kill(context.Context, syscall.Signal) error
|
Kill(context.Context, syscall.Signal, ...KillOpts) error
|
||||||
// Wait blocks until the process has exited returning the exit status
|
// Wait asynchronously waits for the process to exit, and sends the exit code to the returned channel
|
||||||
Wait(context.Context) (uint32, error)
|
Wait(context.Context) (<-chan ExitStatus, error)
|
||||||
// CloseIO allows various pipes to be closed on the process
|
// CloseIO allows various pipes to be closed on the process
|
||||||
CloseIO(context.Context, ...IOCloserOpts) error
|
CloseIO(context.Context, ...IOCloserOpts) error
|
||||||
// Resize changes the width and heigh of the process's terminal
|
// Resize changes the width and heigh of the process's terminal
|
||||||
|
@ -36,12 +36,46 @@ type Process interface {
|
||||||
Status(context.Context) (Status, error)
|
Status(context.Context) (Status, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExitStatus encapsulates a process' exit status.
|
||||||
|
// It is used by `Wait()` to return either a process exit code or an error
|
||||||
|
type ExitStatus struct {
|
||||||
|
code uint32
|
||||||
|
exitedAt time.Time
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result returns the exit code and time of the exit status.
|
||||||
|
// An error may be returned here to which indicates there was an error
|
||||||
|
// at some point while waiting for the exit status. It does not signify
|
||||||
|
// an error with the process itself.
|
||||||
|
// If an error is returned, the process may still be running.
|
||||||
|
func (s ExitStatus) Result() (uint32, time.Time, error) {
|
||||||
|
return s.code, s.exitedAt, s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitCode returns the exit code of the process.
|
||||||
|
// This is only valid is Error() returns nil
|
||||||
|
func (s ExitStatus) ExitCode() uint32 {
|
||||||
|
return s.code
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitTime returns the exit time of the process
|
||||||
|
// This is only valid is Error() returns nil
|
||||||
|
func (s ExitStatus) ExitTime() time.Time {
|
||||||
|
return s.exitedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the error, if any, that occured while waiting for the
|
||||||
|
// process.
|
||||||
|
func (s ExitStatus) Error() error {
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
type process struct {
|
type process struct {
|
||||||
id string
|
id string
|
||||||
task *task
|
task *task
|
||||||
pid uint32
|
pid uint32
|
||||||
io IO
|
io IO
|
||||||
spec *specs.Process
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) ID() string {
|
func (p *process) ID() string {
|
||||||
|
@ -70,48 +104,71 @@ func (p *process) Start(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) Kill(ctx context.Context, s syscall.Signal) error {
|
func (p *process) Kill(ctx context.Context, s syscall.Signal, opts ...KillOpts) error {
|
||||||
|
var i KillInfo
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(ctx, p, &i); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
_, err := p.task.client.TaskService().Kill(ctx, &tasks.KillRequest{
|
_, err := p.task.client.TaskService().Kill(ctx, &tasks.KillRequest{
|
||||||
Signal: uint32(s),
|
Signal: uint32(s),
|
||||||
ContainerID: p.task.id,
|
ContainerID: p.task.id,
|
||||||
ExecID: p.id,
|
ExecID: p.id,
|
||||||
|
All: i.All,
|
||||||
})
|
})
|
||||||
return errdefs.FromGRPC(err)
|
return errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) Wait(ctx context.Context) (uint32, error) {
|
func (p *process) Wait(ctx context.Context) (<-chan ExitStatus, error) {
|
||||||
cancellable, cancel := context.WithCancel(ctx)
|
cancellable, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
|
||||||
eventstream, err := p.task.client.EventService().Subscribe(cancellable, &eventsapi.SubscribeRequest{
|
eventstream, err := p.task.client.EventService().Subscribe(cancellable, &eventsapi.SubscribeRequest{
|
||||||
Filters: []string{"topic==" + runtime.TaskExitEventTopic},
|
Filters: []string{"topic==" + runtime.TaskExitEventTopic},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, err
|
cancel()
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
// first check if the task has exited
|
// first check if the task has exited
|
||||||
status, err := p.Status(ctx)
|
status, err := p.Status(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, errdefs.FromGRPC(err)
|
cancel()
|
||||||
|
return nil, errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chStatus := make(chan ExitStatus, 1)
|
||||||
if status.Status == Stopped {
|
if status.Status == Stopped {
|
||||||
return status.ExitStatus, nil
|
cancel()
|
||||||
|
chStatus <- ExitStatus{code: status.ExitStatus, exitedAt: status.ExitTime}
|
||||||
|
return chStatus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer cancel()
|
||||||
|
chStatus <- ExitStatus{} // signal that the goroutine is running
|
||||||
for {
|
for {
|
||||||
evt, err := eventstream.Recv()
|
evt, err := eventstream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, err
|
chStatus <- ExitStatus{code: UnknownExitStatus, err: err}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) {
|
if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) {
|
||||||
v, err := typeurl.UnmarshalAny(evt.Event)
|
v, err := typeurl.UnmarshalAny(evt.Event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, err
|
chStatus <- ExitStatus{code: UnknownExitStatus, err: err}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
e := v.(*eventsapi.TaskExit)
|
e := v.(*eventsapi.TaskExit)
|
||||||
if e.ID == p.id && e.ContainerID == p.task.id {
|
if e.ID == p.id && e.ContainerID == p.task.id {
|
||||||
return e.ExitStatus, nil
|
chStatus <- ExitStatus{code: e.ExitStatus, exitedAt: e.ExitedAt}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-chStatus // wait for the goroutine to be running
|
||||||
|
return chStatus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) CloseIO(ctx context.Context, opts ...IOCloserOpts) error {
|
func (p *process) CloseIO(ctx context.Context, opts ...IOCloserOpts) error {
|
||||||
|
@ -142,31 +199,32 @@ func (p *process) Resize(ctx context.Context, w, h uint32) error {
|
||||||
return errdefs.FromGRPC(err)
|
return errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, error) {
|
func (p *process) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStatus, error) {
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
if err := o(ctx, p); err != nil {
|
if err := o(ctx, p); err != nil {
|
||||||
return UnknownExitStatus, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status, err := p.Status(ctx)
|
status, err := p.Status(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if status.Status != Stopped {
|
switch status.Status {
|
||||||
return UnknownExitStatus, errors.Wrapf(errdefs.ErrFailedPrecondition, "process must be stopped before deletion")
|
case Running, Paused, Pausing:
|
||||||
}
|
return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "process must be stopped before deletion")
|
||||||
if p.io != nil {
|
|
||||||
p.io.Wait()
|
|
||||||
p.io.Close()
|
|
||||||
}
|
}
|
||||||
r, err := p.task.client.TaskService().DeleteProcess(ctx, &tasks.DeleteProcessRequest{
|
r, err := p.task.client.TaskService().DeleteProcess(ctx, &tasks.DeleteProcessRequest{
|
||||||
ContainerID: p.task.id,
|
ContainerID: p.task.id,
|
||||||
ExecID: p.id,
|
ExecID: p.id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, errdefs.FromGRPC(err)
|
return nil, errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
return r.ExitStatus, nil
|
if p.io != nil {
|
||||||
|
p.io.Wait()
|
||||||
|
p.io.Close()
|
||||||
|
}
|
||||||
|
return &ExitStatus{code: r.ExitStatus, exitedAt: r.ExitedAt}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) Status(ctx context.Context) (Status, error) {
|
func (p *process) Status(ctx context.Context) (Status, error) {
|
||||||
|
|
|
@ -31,6 +31,11 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, err = contextWithRepositoryScope(ctx, r.refspec, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
u := r.url(path)
|
u := r.url(path)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,10 @@ type dockerPusher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
|
func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
|
||||||
|
ctx, err := contextWithRepositoryScope(ctx, p.refspec, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
ref := remotes.MakeRefKey(ctx, desc)
|
ref := remotes.MakeRefKey(ctx, desc)
|
||||||
status, err := p.tracker.GetStatus(ref)
|
status, err := p.tracker.GetStatus(ref)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -109,7 +113,10 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusAccepted {
|
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK, http.StatusAccepted, http.StatusNoContent:
|
||||||
|
default:
|
||||||
// TODO: log error
|
// TODO: log error
|
||||||
return nil, errors.Errorf("unexpected response: %s", resp.Status)
|
return nil, errors.Errorf("unexpected response: %s", resp.Status)
|
||||||
}
|
}
|
||||||
|
@ -155,7 +162,10 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
|
||||||
pr.CloseWithError(err)
|
pr.CloseWithError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusCreated {
|
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent:
|
||||||
|
default:
|
||||||
// TODO: log error
|
// TODO: log error
|
||||||
pr.CloseWithError(errors.Errorf("unexpected response: %s", resp.Status))
|
pr.CloseWithError(errors.Errorf("unexpected response: %s", resp.Status))
|
||||||
}
|
}
|
||||||
|
@ -215,7 +225,7 @@ func (pw *pushWriter) Digest() digest.Digest {
|
||||||
return pw.expected
|
return pw.expected
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *pushWriter) Commit(size int64, expected digest.Digest, opts ...content.Opt) error {
|
func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
|
||||||
// Check whether read has already thrown an error
|
// Check whether read has already thrown an error
|
||||||
if _, err := pw.pipe.Write([]byte{}); err != nil && err != io.ErrClosedPipe {
|
if _, err := pw.pipe.Write([]byte{}); err != nil && err != io.ErrClosedPipe {
|
||||||
return errors.Wrap(err, "pipe error before commit")
|
return errors.Wrap(err, "pipe error before commit")
|
||||||
|
@ -232,6 +242,14 @@ func (pw *pushWriter) Commit(size int64, expected digest.Digest, opts ...content
|
||||||
return errors.New("no response")
|
return errors.New("no response")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 201 is specified return status, some registries return
|
||||||
|
// 200 or 204.
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent:
|
||||||
|
default:
|
||||||
|
return errors.Errorf("unexpected status: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
status, err := pw.tracker.GetStatus(pw.ref)
|
status, err := pw.tracker.GetStatus(pw.ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get status")
|
return errors.Wrap(err, "failed to get status")
|
||||||
|
|
|
@ -116,6 +116,10 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
|
||||||
urls = append(urls, fetcher.url("manifests", refspec.Object))
|
urls = append(urls, fetcher.url("manifests", refspec.Object))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, err = contextWithRepositoryScope(ctx, refspec, false)
|
||||||
|
if err != nil {
|
||||||
|
return "", ocispec.Descriptor{}, err
|
||||||
|
}
|
||||||
for _, u := range urls {
|
for _, u := range urls {
|
||||||
req, err := http.NewRequest(http.MethodHead, u, nil)
|
req, err := http.NewRequest(http.MethodHead, u, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -228,6 +232,7 @@ func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher
|
||||||
}
|
}
|
||||||
|
|
||||||
type dockerBase struct {
|
type dockerBase struct {
|
||||||
|
refspec reference.Spec
|
||||||
base url.URL
|
base url.URL
|
||||||
token string
|
token string
|
||||||
|
|
||||||
|
@ -268,6 +273,7 @@ func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) {
|
||||||
base.Path = path.Join("/v2", prefix)
|
base.Path = path.Join("/v2", prefix)
|
||||||
|
|
||||||
return &dockerBase{
|
return &dockerBase{
|
||||||
|
refspec: refspec,
|
||||||
base: base,
|
base: base,
|
||||||
client: r.client,
|
client: r.client,
|
||||||
username: username,
|
username: username,
|
||||||
|
@ -313,9 +319,11 @@ func (r *dockerBase) doRequestWithRetries(ctx context.Context, req *http.Request
|
||||||
responses = append(responses, resp)
|
responses = append(responses, resp)
|
||||||
req, err = r.retryRequest(ctx, req, responses)
|
req, err = r.retryRequest(ctx, req, responses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
resp.Body.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if req != nil {
|
if req != nil {
|
||||||
|
resp.Body.Close()
|
||||||
return r.doRequestWithRetries(ctx, req, responses)
|
return r.doRequestWithRetries(ctx, req, responses)
|
||||||
}
|
}
|
||||||
return resp, err
|
return resp, err
|
||||||
|
@ -428,14 +436,10 @@ func (r *dockerBase) setTokenAuth(ctx context.Context, params map[string]string)
|
||||||
service: params["service"],
|
service: params["service"],
|
||||||
}
|
}
|
||||||
|
|
||||||
scope, ok := params["scope"]
|
to.scopes = getTokenScopes(ctx, params)
|
||||||
if !ok {
|
if len(to.scopes) == 0 {
|
||||||
return errors.Errorf("no scope specified for token auth challenge")
|
return errors.Errorf("no scope specified for token auth challenge")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Get added scopes from context
|
|
||||||
to.scopes = []string{scope}
|
|
||||||
|
|
||||||
if r.secret != "" {
|
if r.secret != "" {
|
||||||
// Credential information is provided, use oauth POST endpoint
|
// Credential information is provided, use oauth POST endpoint
|
||||||
r.token, err = r.fetchTokenWithOAuth(ctx, to)
|
r.token, err = r.fetchTokenWithOAuth(ctx, to)
|
||||||
|
@ -489,8 +493,9 @@ func (r *dockerBase) fetchTokenWithOAuth(ctx context.Context, to tokenOptions) (
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode == 405 && r.username != "" {
|
// Registries without support for POST may return 404 for POST /v2/token.
|
||||||
// It would be nice if registries would implement the specifications
|
// As of September 2017, GCR is known to return 404.
|
||||||
|
if (resp.StatusCode == 405 && r.username != "") || resp.StatusCode == 404 {
|
||||||
return r.getToken(ctx, to)
|
return r.getToken(ctx, to)
|
||||||
} else if resp.StatusCode < 200 || resp.StatusCode >= 400 {
|
} else if resp.StatusCode < 200 || resp.StatusCode >= 400 {
|
||||||
b, _ := ioutil.ReadAll(resp.Body)
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
|
@ -252,7 +252,7 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
|
||||||
|
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
defer pw.Close()
|
defer pw.Close()
|
||||||
return content.Copy(cw, io.TeeReader(rc, pw), desc.Size, desc.Digest)
|
return content.Copy(ctx, cw, io.TeeReader(rc, pw), desc.Size, desc.Digest)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := eg.Wait(); err != nil {
|
if err := eg.Wait(); err != nil {
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/reference"
|
||||||
|
)
|
||||||
|
|
||||||
|
// repositoryScope returns a repository scope string such as "repository:foo/bar:pull"
|
||||||
|
// for "host/foo/bar:baz".
|
||||||
|
// When push is true, both pull and push are added to the scope.
|
||||||
|
func repositoryScope(refspec reference.Spec, push bool) (string, error) {
|
||||||
|
u, err := url.Parse("dummy://" + refspec.Locator)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s := "repository:" + strings.TrimPrefix(u.Path, "/") + ":pull"
|
||||||
|
if push {
|
||||||
|
s += ",push"
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenScopesKey is used for the key for context.WithValue().
|
||||||
|
// value: []string (e.g. {"registry:foo/bar:pull"})
|
||||||
|
type tokenScopesKey struct{}
|
||||||
|
|
||||||
|
// contextWithRepositoryScope returns a context with tokenScopesKey{} and the repository scope value.
|
||||||
|
func contextWithRepositoryScope(ctx context.Context, refspec reference.Spec, push bool) (context.Context, error) {
|
||||||
|
s, err := repositoryScope(refspec, push)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return context.WithValue(ctx, tokenScopesKey{}, []string{s}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTokenScopes returns deduplicated and sorted scopes from ctx.Value(tokenScopesKey{}) and params["scope"].
|
||||||
|
func getTokenScopes(ctx context.Context, params map[string]string) []string {
|
||||||
|
var scopes []string
|
||||||
|
if x := ctx.Value(tokenScopesKey{}); x != nil {
|
||||||
|
scopes = append(scopes, x.([]string)...)
|
||||||
|
}
|
||||||
|
if scope, ok := params["scope"]; ok {
|
||||||
|
for _, s := range scopes {
|
||||||
|
// Note: this comparison is unaware of the scope grammar (https://docs.docker.com/registry/spec/auth/scope/)
|
||||||
|
// So, "repository:foo/bar:pull,push" != "repository:foo/bar:push,pull", although semantically they are equal.
|
||||||
|
if s == scope {
|
||||||
|
// already appended
|
||||||
|
goto Sort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scopes = append(scopes, scope)
|
||||||
|
}
|
||||||
|
Sort:
|
||||||
|
sort.Strings(scopes)
|
||||||
|
return scopes
|
||||||
|
}
|
|
@ -101,7 +101,7 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
|
||||||
}
|
}
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
|
|
||||||
return content.Copy(cw, rc, desc.Size, desc.Digest)
|
return content.Copy(ctx, cw, rc, desc.Size, desc.Digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushHandler returns a handler that will push all content from the provider
|
// PushHandler returns a handler that will push all content from the provider
|
||||||
|
@ -139,5 +139,5 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc oc
|
||||||
defer ra.Close()
|
defer ra.Close()
|
||||||
|
|
||||||
rd := io.NewSectionReader(ra, 0, desc.Size)
|
rd := io.NewSectionReader(ra, 0, desc.Size)
|
||||||
return content.Copy(cw, rd, desc.Size, desc.Digest)
|
return content.Copy(ctx, cw, rd, desc.Size, desc.Digest)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package rootfs
|
package rootfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
|
@ -63,7 +66,7 @@ func ApplyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snap
|
||||||
return false, errors.Wrap(err, "failed to stat snapshot")
|
return false, errors.Wrap(err, "failed to stat snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
key := fmt.Sprintf("extract %s", chainID)
|
key := fmt.Sprintf("extract-%s %s", uniquePart(), chainID)
|
||||||
|
|
||||||
// Prepare snapshot with from parent
|
// Prepare snapshot with from parent
|
||||||
mounts, err := sn.Prepare(ctx, key, parent.String())
|
mounts, err := sn.Prepare(ctx, key, parent.String())
|
||||||
|
@ -90,8 +93,25 @@ func ApplyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snap
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = sn.Commit(ctx, chainID.String(), key); err != nil {
|
if err = sn.Commit(ctx, chainID.String(), key); err != nil {
|
||||||
|
if !errdefs.IsAlreadyExists(err) {
|
||||||
return false, errors.Wrapf(err, "failed to commit snapshot %s", parent)
|
return false, errors.Wrapf(err, "failed to commit snapshot %s", parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destination already exists, cleanup key and return without error
|
||||||
|
err = nil
|
||||||
|
if err := sn.Remove(ctx, key); err != nil {
|
||||||
|
return false, errors.Wrapf(err, "failed to cleanup aborted apply %s", key)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uniquePart() string {
|
||||||
|
t := time.Now()
|
||||||
|
var b [3]byte
|
||||||
|
// Ignore read failures, just decreases uniqueness
|
||||||
|
rand.Read(b[:])
|
||||||
|
return fmt.Sprintf("%d-%s", t.Nanosecond(), base64.URLEncoding.EncodeToString(b[:]))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package rootfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/containerd/containerd/mount"
|
||||||
|
"github.com/containerd/containerd/snapshot"
|
||||||
|
digest "github.com/opencontainers/go-digest"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
initializers = map[string]initializerFunc{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type initializerFunc func(string) error
|
||||||
|
|
||||||
|
type Mounter interface {
|
||||||
|
Mount(target string, mounts ...mount.Mount) error
|
||||||
|
Unmount(target string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitRootFS(ctx context.Context, name string, parent digest.Digest, readonly bool, snapshotter snapshot.Snapshotter, mounter Mounter) ([]mount.Mount, error) {
|
||||||
|
_, err := snapshotter.Stat(ctx, name)
|
||||||
|
if err == nil {
|
||||||
|
return nil, errors.Errorf("rootfs already exists")
|
||||||
|
}
|
||||||
|
// TODO: ensure not exist error once added to snapshot package
|
||||||
|
|
||||||
|
parentS := parent.String()
|
||||||
|
|
||||||
|
initName := defaultInitializer
|
||||||
|
initFn := initializers[initName]
|
||||||
|
if initFn != nil {
|
||||||
|
parentS, err = createInitLayer(ctx, parentS, initName, initFn, snapshotter, mounter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if readonly {
|
||||||
|
return snapshotter.View(ctx, name, parentS)
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshotter.Prepare(ctx, name, parentS)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createInitLayer(ctx context.Context, parent, initName string, initFn func(string) error, snapshotter snapshot.Snapshotter, mounter Mounter) (string, error) {
|
||||||
|
initS := fmt.Sprintf("%s %s", parent, initName)
|
||||||
|
if _, err := snapshotter.Stat(ctx, initS); err == nil {
|
||||||
|
return initS, nil
|
||||||
|
}
|
||||||
|
// TODO: ensure not exist error once added to snapshot package
|
||||||
|
|
||||||
|
// Create tempdir
|
||||||
|
td, err := ioutil.TempDir("", "create-init-")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(td)
|
||||||
|
|
||||||
|
mounts, err := snapshotter.Prepare(ctx, td, parent)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
// TODO: once implemented uncomment
|
||||||
|
//if rerr := snapshotter.Remove(ctx, td); rerr != nil {
|
||||||
|
// log.G(ctx).Errorf("Failed to remove snapshot %s: %v", td, merr)
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = mounter.Mount(td, mounts...); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = initFn(td); err != nil {
|
||||||
|
if merr := mounter.Unmount(td); merr != nil {
|
||||||
|
log.G(ctx).Errorf("Failed to unmount %s: %v", td, merr)
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mounter.Unmount(td); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := snapshotter.Commit(ctx, initS, td); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return initS, nil
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
package rootfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultInitializer = "linux-init"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initializers[defaultInitializer] = initFS
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDirectory(name string, uid, gid int) initializerFunc {
|
||||||
|
return func(root string) error {
|
||||||
|
dname := filepath.Join(root, name)
|
||||||
|
st, err := os.Stat(dname)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
} else if err == nil {
|
||||||
|
if st.IsDir() {
|
||||||
|
stat := st.Sys().(*syscall.Stat_t)
|
||||||
|
if int(stat.Gid) == gid && int(stat.Uid) == uid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := os.Remove(dname); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.Mkdir(dname, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := os.Mkdir(dname, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Chown(dname, uid, gid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func touchFile(name string, uid, gid int) initializerFunc {
|
||||||
|
return func(root string) error {
|
||||||
|
fname := filepath.Join(root, name)
|
||||||
|
|
||||||
|
st, err := os.Stat(fname)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
} else if err == nil {
|
||||||
|
stat := st.Sys().(*syscall.Stat_t)
|
||||||
|
if int(stat.Gid) == gid && int(stat.Uid) == uid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.Chown(fname, uid, gid)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(fname, os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return f.Chown(uid, gid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func symlink(oldname, newname string) initializerFunc {
|
||||||
|
return func(root string) error {
|
||||||
|
linkName := filepath.Join(root, newname)
|
||||||
|
if _, err := os.Stat(linkName); err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
} else if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.Symlink(oldname, linkName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initFS(root string) error {
|
||||||
|
st, err := os.Stat(root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stat := st.Sys().(*syscall.Stat_t)
|
||||||
|
uid := int(stat.Uid)
|
||||||
|
gid := int(stat.Gid)
|
||||||
|
|
||||||
|
initFuncs := []initializerFunc{
|
||||||
|
createDirectory("/dev", uid, gid),
|
||||||
|
createDirectory("/dev/pts", uid, gid),
|
||||||
|
createDirectory("/dev/shm", uid, gid),
|
||||||
|
touchFile("/dev/console", uid, gid),
|
||||||
|
createDirectory("/proc", uid, gid),
|
||||||
|
createDirectory("/sys", uid, gid),
|
||||||
|
createDirectory("/etc", uid, gid),
|
||||||
|
touchFile("/etc/resolv.conf", uid, gid),
|
||||||
|
touchFile("/etc/hosts", uid, gid),
|
||||||
|
touchFile("/etc/hostname", uid, gid),
|
||||||
|
symlink("/proc/mounts", "/etc/mtab"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range initFuncs {
|
||||||
|
if err := fn(root); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package rootfs
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultInitializer = ""
|
||||||
|
)
|
|
@ -7,7 +7,9 @@ const (
|
||||||
TaskExitEventTopic = "/tasks/exit"
|
TaskExitEventTopic = "/tasks/exit"
|
||||||
TaskDeleteEventTopic = "/tasks/delete"
|
TaskDeleteEventTopic = "/tasks/delete"
|
||||||
TaskExecAddedEventTopic = "/tasks/exec-added"
|
TaskExecAddedEventTopic = "/tasks/exec-added"
|
||||||
|
TaskExecStartedEventTopic = "/tasks/exec-started"
|
||||||
TaskPausedEventTopic = "/tasks/paused"
|
TaskPausedEventTopic = "/tasks/paused"
|
||||||
TaskResumedEventTopic = "/tasks/resumed"
|
TaskResumedEventTopic = "/tasks/resumed"
|
||||||
TaskCheckpointedEventTopic = "/tasks/checkpointed"
|
TaskCheckpointedEventTopic = "/tasks/checkpointed"
|
||||||
|
TaskUnknownTopic = "/tasks/?"
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gogo/protobuf/types"
|
"github.com/gogo/protobuf/types"
|
||||||
)
|
)
|
||||||
|
@ -48,6 +49,8 @@ type Task interface {
|
||||||
Update(context.Context, *types.Any) error
|
Update(context.Context, *types.Any) error
|
||||||
// Process returns a process within the task for the provided id
|
// Process returns a process within the task for the provided id
|
||||||
Process(context.Context, string) (Process, error)
|
Process(context.Context, string) (Process, error)
|
||||||
|
// Metrics returns runtime specific metrics for a task
|
||||||
|
Metrics(context.Context) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecOpts struct {
|
type ExecOpts struct {
|
||||||
|
@ -77,8 +80,11 @@ type State struct {
|
||||||
// Pid is the main process id for the container
|
// Pid is the main process id for the container
|
||||||
Pid uint32
|
Pid uint32
|
||||||
// ExitStatus of the process
|
// ExitStatus of the process
|
||||||
// Only vaid if the Status is Stopped
|
// Only valid if the Status is Stopped
|
||||||
ExitStatus uint32
|
ExitStatus uint32
|
||||||
|
// ExitedAt is the time at which the process exited
|
||||||
|
// Only valid if the Status is Stopped
|
||||||
|
ExitedAt time.Time
|
||||||
Stdin string
|
Stdin string
|
||||||
Stdout string
|
Stdout string
|
||||||
Stderr string
|
Stderr string
|
||||||
|
|
|
@ -2,10 +2,10 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -75,7 +75,7 @@ func (l *TaskList) AddWithNamespace(namespace string, t Task) error {
|
||||||
l.tasks[namespace] = make(map[string]Task)
|
l.tasks[namespace] = make(map[string]Task)
|
||||||
}
|
}
|
||||||
if _, ok := l.tasks[namespace][id]; ok {
|
if _, ok := l.tasks[namespace][id]; ok {
|
||||||
return ErrTaskAlreadyExists
|
return errors.Wrap(ErrTaskAlreadyExists, id)
|
||||||
}
|
}
|
||||||
l.tasks[namespace][id] = t
|
l.tasks[namespace][id] = t
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -424,7 +424,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
||||||
if req.Labels != nil {
|
if req.Labels != nil {
|
||||||
opts = append(opts, content.WithLabels(req.Labels))
|
opts = append(opts, content.WithLabels(req.Labels))
|
||||||
}
|
}
|
||||||
if err := wr.Commit(total, expected, opts...); err != nil {
|
if err := wr.Commit(ctx, total, expected, opts...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package content
|
package content
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
contentapi "github.com/containerd/containerd/api/services/content/v1"
|
contentapi "github.com/containerd/containerd/api/services/content/v1"
|
||||||
|
@ -80,7 +81,7 @@ func (rw *remoteWriter) Write(p []byte) (n int, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *remoteWriter) Commit(size int64, expected digest.Digest, opts ...content.Opt) error {
|
func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
|
||||||
var base content.Info
|
var base content.Info
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if err := opt(&base); err != nil {
|
if err := opt(&base); err != nil {
|
||||||
|
|
|
@ -6,10 +6,22 @@ import (
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
// Order is the order of preference in which to try diff algorithms, the
|
||||||
|
// first differ which is supported is used.
|
||||||
|
// Note when multiple differs may be supported, this order will be
|
||||||
|
// respected for which is choosen. Each differ should return the same
|
||||||
|
// correct output, allowing any ordering to be used to prefer
|
||||||
|
// more optimimal implementations.
|
||||||
|
Order []string `toml:"default,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
plugin.Register(&plugin.Registration{
|
plugin.Register(&plugin.Registration{
|
||||||
Type: plugin.GRPCPlugin,
|
Type: plugin.GRPCPlugin,
|
||||||
|
@ -17,20 +29,34 @@ func init() {
|
||||||
Requires: []plugin.PluginType{
|
Requires: []plugin.PluginType{
|
||||||
plugin.DiffPlugin,
|
plugin.DiffPlugin,
|
||||||
},
|
},
|
||||||
|
Config: &config{
|
||||||
|
Order: []string{"walking"},
|
||||||
|
},
|
||||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||||
d, err := ic.Get(plugin.DiffPlugin)
|
differs, err := ic.GetAll(plugin.DiffPlugin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orderedNames := ic.Config.(*config).Order
|
||||||
|
ordered := make([]plugin.Differ, len(orderedNames))
|
||||||
|
for i, n := range orderedNames {
|
||||||
|
differ, ok := differs[n]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.Errorf("needed differ not loaded: %s", n)
|
||||||
|
}
|
||||||
|
ordered[i] = differ.(plugin.Differ)
|
||||||
|
}
|
||||||
|
|
||||||
return &service{
|
return &service{
|
||||||
diff: d.(plugin.Differ),
|
differs: ordered,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
diff plugin.Differ
|
differs []plugin.Differ
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Register(gs *grpc.Server) error {
|
func (s *service) Register(gs *grpc.Server) error {
|
||||||
|
@ -39,12 +65,20 @@ func (s *service) Register(gs *grpc.Server) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Apply(ctx context.Context, er *diffapi.ApplyRequest) (*diffapi.ApplyResponse, error) {
|
func (s *service) Apply(ctx context.Context, er *diffapi.ApplyRequest) (*diffapi.ApplyResponse, error) {
|
||||||
desc := toDescriptor(er.Diff)
|
var (
|
||||||
// TODO: Check for supported media types
|
ocidesc ocispec.Descriptor
|
||||||
|
err error
|
||||||
|
desc = toDescriptor(er.Diff)
|
||||||
|
mounts = toMounts(er.Mounts)
|
||||||
|
)
|
||||||
|
|
||||||
mounts := toMounts(er.Mounts)
|
for _, differ := range s.differs {
|
||||||
|
ocidesc, err = differ.Apply(ctx, desc, mounts)
|
||||||
|
if !errdefs.IsNotImplemented(err) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ocidesc, err := s.diff.Apply(ctx, desc, mounts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errdefs.ToGRPC(err)
|
return nil, errdefs.ToGRPC(err)
|
||||||
}
|
}
|
||||||
|
@ -56,10 +90,19 @@ func (s *service) Apply(ctx context.Context, er *diffapi.ApplyRequest) (*diffapi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Diff(ctx context.Context, dr *diffapi.DiffRequest) (*diffapi.DiffResponse, error) {
|
func (s *service) Diff(ctx context.Context, dr *diffapi.DiffRequest) (*diffapi.DiffResponse, error) {
|
||||||
aMounts := toMounts(dr.Left)
|
var (
|
||||||
bMounts := toMounts(dr.Right)
|
ocidesc ocispec.Descriptor
|
||||||
|
err error
|
||||||
|
aMounts = toMounts(dr.Left)
|
||||||
|
bMounts = toMounts(dr.Right)
|
||||||
|
)
|
||||||
|
|
||||||
ocidesc, err := s.diff.DiffMounts(ctx, aMounts, bMounts, dr.MediaType, dr.Ref)
|
for _, differ := range s.differs {
|
||||||
|
ocidesc, err = differ.DiffMounts(ctx, aMounts, bMounts, dr.MediaType, dr.Ref)
|
||||||
|
if !errdefs.IsNotImplemented(err) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errdefs.ToGRPC(err)
|
return nil, errdefs.ToGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
package snapshot
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultSnapshotter = "overlayfs"
|
|
||||||
)
|
|
|
@ -1,7 +0,0 @@
|
||||||
// +build darwin freebsd solaris
|
|
||||||
|
|
||||||
package snapshot
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultSnapshotter = "naive"
|
|
||||||
)
|
|
|
@ -1,5 +0,0 @@
|
||||||
package snapshot
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultSnapshotter = "windows"
|
|
||||||
)
|
|
|
@ -20,11 +20,6 @@ import (
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
|
||||||
// Default is the default snapshotter to use for the service
|
|
||||||
Default string `toml:"default,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
plugin.Register(&plugin.Registration{
|
plugin.Register(&plugin.Registration{
|
||||||
Type: plugin.GRPCPlugin,
|
Type: plugin.GRPCPlugin,
|
||||||
|
@ -33,9 +28,6 @@ func init() {
|
||||||
plugin.SnapshotPlugin,
|
plugin.SnapshotPlugin,
|
||||||
plugin.MetadataPlugin,
|
plugin.MetadataPlugin,
|
||||||
},
|
},
|
||||||
Config: &config{
|
|
||||||
Default: defaultSnapshotter,
|
|
||||||
},
|
|
||||||
Init: newService,
|
Init: newService,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -44,7 +36,6 @@ var empty = &protoempty.Empty{}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
snapshotters map[string]snapshot.Snapshotter
|
snapshotters map[string]snapshot.Snapshotter
|
||||||
defaultSnapshotterName string
|
|
||||||
publisher events.Publisher
|
publisher events.Publisher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,26 +53,24 @@ func newService(ic *plugin.InitContext) (interface{}, error) {
|
||||||
snapshotters[name] = metadata.NewSnapshotter(md.(*bolt.DB), name, sn.(snapshot.Snapshotter))
|
snapshotters[name] = metadata.NewSnapshotter(md.(*bolt.DB), name, sn.(snapshot.Snapshotter))
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := ic.Config.(*config)
|
if len(snapshotters) == 0 {
|
||||||
_, ok := snapshotters[cfg.Default]
|
return nil, errors.Errorf("failed to create snapshotter service: no snapshotters loaded")
|
||||||
if !ok {
|
|
||||||
return nil, errors.Errorf("default snapshotter not loaded: %s", cfg.Default)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &service{
|
return &service{
|
||||||
snapshotters: snapshotters,
|
snapshotters: snapshotters,
|
||||||
defaultSnapshotterName: cfg.Default,
|
|
||||||
publisher: ic.Events,
|
publisher: ic.Events,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) getSnapshotter(name string) (snapshot.Snapshotter, error) {
|
func (s *service) getSnapshotter(name string) (snapshot.Snapshotter, error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = s.defaultSnapshotterName
|
return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "snapshotter argument missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
sn, ok := s.snapshotters[name]
|
sn, ok := s.snapshotters[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("snapshotter not loaded: %s", name)
|
return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "snapshotter not loaded: %s", name)
|
||||||
}
|
}
|
||||||
return sn, nil
|
return sn, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package snapshot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
|
@ -12,11 +14,26 @@ type Kind uint8
|
||||||
|
|
||||||
// definitions of snapshot kinds
|
// definitions of snapshot kinds
|
||||||
const (
|
const (
|
||||||
KindView Kind = iota + 1
|
KindUnknown Kind = iota
|
||||||
|
KindView
|
||||||
KindActive
|
KindActive
|
||||||
KindCommitted
|
KindCommitted
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ParseKind(s string) Kind {
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
switch s {
|
||||||
|
case "view":
|
||||||
|
return KindView
|
||||||
|
case "active":
|
||||||
|
return KindActive
|
||||||
|
case "committed":
|
||||||
|
return KindCommitted
|
||||||
|
}
|
||||||
|
|
||||||
|
return KindUnknown
|
||||||
|
}
|
||||||
|
|
||||||
func (k Kind) String() string {
|
func (k Kind) String() string {
|
||||||
switch k {
|
switch k {
|
||||||
case KindView:
|
case KindView:
|
||||||
|
@ -25,19 +42,34 @@ func (k Kind) String() string {
|
||||||
return "Active"
|
return "Active"
|
||||||
case KindCommitted:
|
case KindCommitted:
|
||||||
return "Committed"
|
return "Committed"
|
||||||
default:
|
}
|
||||||
|
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k Kind) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *Kind) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(b, &s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*k = ParseKind(s)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info provides information about a particular snapshot.
|
// Info provides information about a particular snapshot.
|
||||||
|
// JSON marshallability is supported for interactive with tools like ctr,
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Kind Kind // active or committed snapshot
|
Kind Kind // active or committed snapshot
|
||||||
Name string // name or key of snapshot
|
Name string // name or key of snapshot
|
||||||
Parent string // name of parent snapshot
|
Parent string `json:",omitempty"` // name of parent snapshot
|
||||||
Labels map[string]string // Labels for snapshot
|
Labels map[string]string `json:",omitempty"` // Labels for snapshot
|
||||||
Created time.Time // Created time
|
Created time.Time `json:",omitempty"` // Created time
|
||||||
Updated time.Time // Last update time
|
Updated time.Time `json:",omitempty"` // Last update time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usage defines statistics for disk resources consumed by the snapshot.
|
// Usage defines statistics for disk resources consumed by the snapshot.
|
||||||
|
|
8
vendor/github.com/containerd/containerd/snapshotter_default_linux.go
generated
vendored
Normal file
8
vendor/github.com/containerd/containerd/snapshotter_default_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultSnapshotter will set the default snapshotter for the platform.
|
||||||
|
// This will be based on the client compilation target, so take that into
|
||||||
|
// account when choosing this value.
|
||||||
|
DefaultSnapshotter = "overlayfs"
|
||||||
|
)
|
10
vendor/github.com/containerd/containerd/snapshotter_default_unix.go
generated
vendored
Normal file
10
vendor/github.com/containerd/containerd/snapshotter_default_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// +build darwin freebsd solaris
|
||||||
|
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultSnapshotter will set the default snapshotter for the platform.
|
||||||
|
// This will be based on the client compilation target, so take that into
|
||||||
|
// account when choosing this value.
|
||||||
|
DefaultSnapshotter = "naive"
|
||||||
|
)
|
8
vendor/github.com/containerd/containerd/snapshotter_default_windows.go
generated
vendored
Normal file
8
vendor/github.com/containerd/containerd/snapshotter_default_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultSnapshotter will set the default snapshotter for the platform.
|
||||||
|
// This will be based on the client compilation target, so take that into
|
||||||
|
// account when choosing this value.
|
||||||
|
DefaultSnapshotter = "windows"
|
||||||
|
)
|
|
@ -1,16 +1,21 @@
|
||||||
package containerd
|
package containerd
|
||||||
|
|
||||||
import specs "github.com/opencontainers/runtime-spec/specs-go"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/containers"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
// GenerateSpec will generate a default spec from the provided image
|
// GenerateSpec will generate a default spec from the provided image
|
||||||
// for use as a containerd container
|
// for use as a containerd container
|
||||||
func GenerateSpec(opts ...SpecOpts) (*specs.Spec, error) {
|
func GenerateSpec(ctx context.Context, client *Client, c *containers.Container, opts ...SpecOpts) (*specs.Spec, error) {
|
||||||
s, err := createDefaultSpec()
|
s, err := createDefaultSpec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
if err := o(s); err != nil {
|
if err := o(ctx, client, c, s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
package containerd
|
package containerd
|
||||||
|
|
||||||
import specs "github.com/opencontainers/runtime-spec/specs-go"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/containers"
|
||||||
|
"github.com/containerd/containerd/typeurl"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
// SpecOpts sets spec specific information to a newly generated OCI spec
|
// SpecOpts sets spec specific information to a newly generated OCI spec
|
||||||
type SpecOpts func(s *specs.Spec) error
|
type SpecOpts func(context.Context, *Client, *containers.Container, *specs.Spec) error
|
||||||
|
|
||||||
// WithProcessArgs replaces the args on the generated spec
|
// WithProcessArgs replaces the args on the generated spec
|
||||||
func WithProcessArgs(args ...string) SpecOpts {
|
func WithProcessArgs(args ...string) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Process.Args = args
|
s.Process.Args = args
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -15,8 +21,46 @@ func WithProcessArgs(args ...string) SpecOpts {
|
||||||
|
|
||||||
// WithHostname sets the container's hostname
|
// WithHostname sets the container's hostname
|
||||||
func WithHostname(name string) SpecOpts {
|
func WithHostname(name string) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Hostname = name
|
s.Hostname = name
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithNewSpec generates a new spec for a new container
|
||||||
|
func WithNewSpec(opts ...SpecOpts) NewContainerOpts {
|
||||||
|
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||||
|
s, err := createDefaultSpec()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(ctx, client, c, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
any, err := typeurl.MarshalAny(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Spec = any
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSpec sets the provided spec on the container
|
||||||
|
func WithSpec(s *specs.Spec, opts ...SpecOpts) NewContainerOpts {
|
||||||
|
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(ctx, client, c, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
any, err := typeurl.MarshalAny(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Spec = any
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,23 +6,30 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
|
"github.com/containerd/containerd/fs"
|
||||||
"github.com/containerd/containerd/images"
|
"github.com/containerd/containerd/images"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
"github.com/containerd/containerd/typeurl"
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/opencontainers/image-spec/identity"
|
"github.com/opencontainers/image-spec/identity"
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/user"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WithTTY sets the information on the spec as well as the environment variables for
|
// WithTTY sets the information on the spec as well as the environment variables for
|
||||||
// using a TTY
|
// using a TTY
|
||||||
func WithTTY(s *specs.Spec) error {
|
func WithTTY(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Process.Terminal = true
|
s.Process.Terminal = true
|
||||||
s.Process.Env = append(s.Process.Env, "TERM=xterm")
|
s.Process.Env = append(s.Process.Env, "TERM=xterm")
|
||||||
return nil
|
return nil
|
||||||
|
@ -30,7 +37,7 @@ func WithTTY(s *specs.Spec) error {
|
||||||
|
|
||||||
// WithHostNamespace allows a task to run inside the host's linux namespace
|
// WithHostNamespace allows a task to run inside the host's linux namespace
|
||||||
func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
|
func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
for i, n := range s.Linux.Namespaces {
|
for i, n := range s.Linux.Namespaces {
|
||||||
if n.Type == ns {
|
if n.Type == ns {
|
||||||
s.Linux.Namespaces = append(s.Linux.Namespaces[:i], s.Linux.Namespaces[i+1:]...)
|
s.Linux.Namespaces = append(s.Linux.Namespaces[:i], s.Linux.Namespaces[i+1:]...)
|
||||||
|
@ -44,7 +51,7 @@ func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
|
||||||
// WithLinuxNamespace uses the passed in namespace for the spec. If a namespace of the same type already exists in the
|
// WithLinuxNamespace uses the passed in namespace for the spec. If a namespace of the same type already exists in the
|
||||||
// spec, the existing namespace is replaced by the one provided.
|
// spec, the existing namespace is replaced by the one provided.
|
||||||
func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts {
|
func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
for i, n := range s.Linux.Namespaces {
|
for i, n := range s.Linux.Namespaces {
|
||||||
if n.Type == ns.Type {
|
if n.Type == ns.Type {
|
||||||
before := s.Linux.Namespaces[:i]
|
before := s.Linux.Namespaces[:i]
|
||||||
|
@ -60,13 +67,13 @@ func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithImageConfig configures the spec to from the configuration of an Image
|
// WithImageConfig configures the spec to from the configuration of an Image
|
||||||
func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
func WithImageConfig(i Image) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(ctx context.Context, client *Client, c *containers.Container, s *specs.Spec) error {
|
||||||
var (
|
var (
|
||||||
image = i.(*image)
|
image = i.(*image)
|
||||||
store = image.client.ContentStore()
|
store = client.ContentStore()
|
||||||
)
|
)
|
||||||
ic, err := image.i.Config(ctx, store)
|
ic, err := image.i.Config(ctx, store, platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -89,9 +96,6 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||||
return fmt.Errorf("unknown image config media type %s", ic.MediaType)
|
return fmt.Errorf("unknown image config media type %s", ic.MediaType)
|
||||||
}
|
}
|
||||||
s.Process.Env = append(s.Process.Env, config.Env...)
|
s.Process.Env = append(s.Process.Env, config.Env...)
|
||||||
var (
|
|
||||||
uid, gid uint32
|
|
||||||
)
|
|
||||||
cmd := config.Cmd
|
cmd := config.Cmd
|
||||||
s.Process.Args = append(config.Entrypoint, cmd...)
|
s.Process.Args = append(config.Entrypoint, cmd...)
|
||||||
if config.User != "" {
|
if config.User != "" {
|
||||||
|
@ -100,24 +104,30 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||||
case 1:
|
case 1:
|
||||||
v, err := strconv.ParseUint(parts[0], 0, 10)
|
v, err := strconv.ParseUint(parts[0], 0, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// if we cannot parse as a uint they try to see if it is a username
|
||||||
|
if err := WithUsername(config.User)(ctx, client, c, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := WithUserID(uint32(v))(ctx, client, c, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uid, gid = uint32(v), uint32(v)
|
|
||||||
case 2:
|
case 2:
|
||||||
v, err := strconv.ParseUint(parts[0], 0, 10)
|
v, err := strconv.ParseUint(parts[0], 0, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uid = uint32(v)
|
uid := uint32(v)
|
||||||
if v, err = strconv.ParseUint(parts[1], 0, 10); err != nil {
|
if v, err = strconv.ParseUint(parts[1], 0, 10); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gid = uint32(v)
|
gid := uint32(v)
|
||||||
|
s.Process.User.UID, s.Process.User.GID = uid, gid
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid USER value %s", config.User)
|
return fmt.Errorf("invalid USER value %s", config.User)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Process.User.UID, s.Process.User.GID = uid, gid
|
|
||||||
cwd := config.WorkingDir
|
cwd := config.WorkingDir
|
||||||
if cwd == "" {
|
if cwd == "" {
|
||||||
cwd = "/"
|
cwd = "/"
|
||||||
|
@ -129,7 +139,7 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||||
|
|
||||||
// WithRootFSPath specifies unmanaged rootfs path.
|
// WithRootFSPath specifies unmanaged rootfs path.
|
||||||
func WithRootFSPath(path string, readonly bool) SpecOpts {
|
func WithRootFSPath(path string, readonly bool) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Root = &specs.Root{
|
s.Root = &specs.Root{
|
||||||
Path: path,
|
Path: path,
|
||||||
Readonly: readonly,
|
Readonly: readonly,
|
||||||
|
@ -139,18 +149,6 @@ func WithRootFSPath(path string, readonly bool) SpecOpts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSpec sets the provided spec for a new container
|
|
||||||
func WithSpec(spec *specs.Spec) NewContainerOpts {
|
|
||||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
|
||||||
any, err := typeurl.MarshalAny(spec)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Spec = any
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithResources sets the provided resources on the spec for task updates
|
// WithResources sets the provided resources on the spec for task updates
|
||||||
func WithResources(resources *specs.LinuxResources) UpdateTaskOpts {
|
func WithResources(resources *specs.LinuxResources) UpdateTaskOpts {
|
||||||
return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error {
|
return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error {
|
||||||
|
@ -160,13 +158,13 @@ func WithResources(resources *specs.LinuxResources) UpdateTaskOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNoNewPrivileges sets no_new_privileges on the process for the container
|
// WithNoNewPrivileges sets no_new_privileges on the process for the container
|
||||||
func WithNoNewPrivileges(s *specs.Spec) error {
|
func WithNoNewPrivileges(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Process.NoNewPrivileges = true
|
s.Process.NoNewPrivileges = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHostHostsFile bind-mounts the host's /etc/hosts into the container as readonly
|
// WithHostHostsFile bind-mounts the host's /etc/hosts into the container as readonly
|
||||||
func WithHostHostsFile(s *specs.Spec) error {
|
func WithHostHostsFile(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Mounts = append(s.Mounts, specs.Mount{
|
s.Mounts = append(s.Mounts, specs.Mount{
|
||||||
Destination: "/etc/hosts",
|
Destination: "/etc/hosts",
|
||||||
Type: "bind",
|
Type: "bind",
|
||||||
|
@ -177,7 +175,7 @@ func WithHostHostsFile(s *specs.Spec) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHostResolvconf bind-mounts the host's /etc/resolv.conf into the container as readonly
|
// WithHostResolvconf bind-mounts the host's /etc/resolv.conf into the container as readonly
|
||||||
func WithHostResolvconf(s *specs.Spec) error {
|
func WithHostResolvconf(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Mounts = append(s.Mounts, specs.Mount{
|
s.Mounts = append(s.Mounts, specs.Mount{
|
||||||
Destination: "/etc/resolv.conf",
|
Destination: "/etc/resolv.conf",
|
||||||
Type: "bind",
|
Type: "bind",
|
||||||
|
@ -188,7 +186,7 @@ func WithHostResolvconf(s *specs.Spec) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHostLocaltime bind-mounts the host's /etc/localtime into the container as readonly
|
// WithHostLocaltime bind-mounts the host's /etc/localtime into the container as readonly
|
||||||
func WithHostLocaltime(s *specs.Spec) error {
|
func WithHostLocaltime(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Mounts = append(s.Mounts, specs.Mount{
|
s.Mounts = append(s.Mounts, specs.Mount{
|
||||||
Destination: "/etc/localtime",
|
Destination: "/etc/localtime",
|
||||||
Type: "bind",
|
Type: "bind",
|
||||||
|
@ -201,7 +199,7 @@ func WithHostLocaltime(s *specs.Spec) error {
|
||||||
// WithUserNamespace sets the uid and gid mappings for the task
|
// WithUserNamespace sets the uid and gid mappings for the task
|
||||||
// this can be called multiple times to add more mappings to the generated spec
|
// this can be called multiple times to add more mappings to the generated spec
|
||||||
func WithUserNamespace(container, host, size uint32) SpecOpts {
|
func WithUserNamespace(container, host, size uint32) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
var hasUserns bool
|
var hasUserns bool
|
||||||
for _, ns := range s.Linux.Namespaces {
|
for _, ns := range s.Linux.Namespaces {
|
||||||
if ns.Type == specs.UserNamespace {
|
if ns.Type == specs.UserNamespace {
|
||||||
|
@ -228,11 +226,23 @@ func WithUserNamespace(container, host, size uint32) SpecOpts {
|
||||||
// WithRemappedSnapshot creates a new snapshot and remaps the uid/gid for the
|
// WithRemappedSnapshot creates a new snapshot and remaps the uid/gid for the
|
||||||
// filesystem to be used by a container with user namespaces
|
// filesystem to be used by a container with user namespaces
|
||||||
func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts {
|
func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts {
|
||||||
|
return withRemappedSnapshotBase(id, i, uid, gid, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRemappedSnapshotView is similar to WithRemappedSnapshot but rootfs is mounted as read-only.
|
||||||
|
func WithRemappedSnapshotView(id string, i Image, uid, gid uint32) NewContainerOpts {
|
||||||
|
return withRemappedSnapshotBase(id, i, uid, gid, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSnapshotterIfEmpty(c)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
snapshotter = client.SnapshotService(c.Snapshotter)
|
snapshotter = client.SnapshotService(c.Snapshotter)
|
||||||
parent = identity.ChainID(diffIDs).String()
|
parent = identity.ChainID(diffIDs).String()
|
||||||
|
@ -242,7 +252,7 @@ func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts
|
||||||
if _, err := snapshotter.Prepare(ctx, id, usernsID); err != nil {
|
if _, err := snapshotter.Prepare(ctx, id, usernsID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.RootFS = id
|
c.SnapshotKey = id
|
||||||
c.Image = i.Name()
|
c.Image = i.Name()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -257,10 +267,15 @@ func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts
|
||||||
if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap"); err != nil {
|
if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := snapshotter.Prepare(ctx, id, usernsID); err != nil {
|
if readonly {
|
||||||
|
_, err = snapshotter.View(ctx, id, usernsID)
|
||||||
|
} else {
|
||||||
|
_, err = snapshotter.Prepare(ctx, id, usernsID)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.RootFS = id
|
c.SnapshotKey = id
|
||||||
c.Image = i.Name()
|
c.Image = i.Name()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -268,7 +283,7 @@ func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts
|
||||||
|
|
||||||
// WithCgroup sets the container's cgroup path
|
// WithCgroup sets the container's cgroup path
|
||||||
func WithCgroup(path string) SpecOpts {
|
func WithCgroup(path string) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Linux.CgroupsPath = path
|
s.Linux.CgroupsPath = path
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -276,13 +291,131 @@ func WithCgroup(path string) SpecOpts {
|
||||||
|
|
||||||
// WithNamespacedCgroup uses the namespace set on the context to create a
|
// WithNamespacedCgroup uses the namespace set on the context to create a
|
||||||
// root directory for containers in the cgroup with the id as the subcgroup
|
// root directory for containers in the cgroup with the id as the subcgroup
|
||||||
func WithNamespacedCgroup(ctx context.Context, id string) SpecOpts {
|
func WithNamespacedCgroup() SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(ctx context.Context, _ *Client, c *containers.Container, s *specs.Spec) error {
|
||||||
namespace, err := namespaces.NamespaceRequired(ctx)
|
namespace, err := namespaces.NamespaceRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Linux.CgroupsPath = filepath.Join("/", namespace, id)
|
s.Linux.CgroupsPath = filepath.Join("/", namespace, c.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUidGid allows the UID and GID for the Process to be set
|
||||||
|
func WithUidGid(uid, gid uint32) SpecOpts {
|
||||||
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
|
s.Process.User.UID = uid
|
||||||
|
s.Process.User.GID = gid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUserID sets the correct UID and GID for the container based
|
||||||
|
// on the image's /etc/passwd contents. If /etc/passwd does not exist,
|
||||||
|
// or uid is not found in /etc/passwd, it sets gid to be the same with
|
||||||
|
// uid, and not returns error.
|
||||||
|
func WithUserID(uid uint32) SpecOpts {
|
||||||
|
return func(ctx context.Context, client *Client, c *containers.Container, s *specs.Spec) error {
|
||||||
|
if c.Snapshotter == "" {
|
||||||
|
return errors.Errorf("no snapshotter set for container")
|
||||||
|
}
|
||||||
|
if c.SnapshotKey == "" {
|
||||||
|
return errors.Errorf("rootfs snapshot not created for container")
|
||||||
|
}
|
||||||
|
snapshotter := client.SnapshotService(c.Snapshotter)
|
||||||
|
mounts, err := snapshotter.Mounts(ctx, c.SnapshotKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
root, err := ioutil.TempDir("", "ctd-username")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
for _, m := range mounts {
|
||||||
|
if err := m.Mount(root); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer unix.Unmount(root, 0)
|
||||||
|
ppath, err := fs.RootPath(root, "/etc/passwd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.Open(ppath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
s.Process.User.UID, s.Process.User.GID = uid, uid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
users, err := user.ParsePasswdFilter(f, func(u user.User) bool {
|
||||||
|
return u.Uid == int(uid)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(users) == 0 {
|
||||||
|
s.Process.User.UID, s.Process.User.GID = uid, uid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
u := users[0]
|
||||||
|
s.Process.User.UID, s.Process.User.GID = uint32(u.Uid), uint32(u.Gid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUsername sets the correct UID and GID for the container
|
||||||
|
// based on the the image's /etc/passwd contents. If /etc/passwd
|
||||||
|
// does not exist, or the username is not found in /etc/passwd,
|
||||||
|
// it returns error.
|
||||||
|
func WithUsername(username string) SpecOpts {
|
||||||
|
return func(ctx context.Context, client *Client, c *containers.Container, s *specs.Spec) error {
|
||||||
|
if c.Snapshotter == "" {
|
||||||
|
return errors.Errorf("no snapshotter set for container")
|
||||||
|
}
|
||||||
|
if c.SnapshotKey == "" {
|
||||||
|
return errors.Errorf("rootfs snapshot not created for container")
|
||||||
|
}
|
||||||
|
snapshotter := client.SnapshotService(c.Snapshotter)
|
||||||
|
mounts, err := snapshotter.Mounts(ctx, c.SnapshotKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
root, err := ioutil.TempDir("", "ctd-username")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
for _, m := range mounts {
|
||||||
|
if err := m.Mount(root); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer unix.Unmount(root, 0)
|
||||||
|
ppath, err := fs.RootPath(root, "/etc/passwd")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.Open(ppath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
users, err := user.ParsePasswdFilter(f, func(u user.User) bool {
|
||||||
|
return u.Name == username
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(users) == 0 {
|
||||||
|
return errors.Errorf("no users found for %s", username)
|
||||||
|
}
|
||||||
|
u := users[0]
|
||||||
|
s.Process.User.UID, s.Process.User.GID = uint32(u.Uid), uint32(u.Gid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,18 @@ 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/typeurl"
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
func WithImageConfig(i Image) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(ctx context.Context, client *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
var (
|
var (
|
||||||
image = i.(*image)
|
image = i.(*image)
|
||||||
store = image.client.ContentStore()
|
store = client.ContentStore()
|
||||||
)
|
)
|
||||||
ic, err := image.i.Config(ctx, store)
|
ic, err := image.i.Config(ctx, store, platforms.Format(platforms.Default()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -52,25 +52,17 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithTTY(width, height int) SpecOpts {
|
func WithTTY(width, height int) SpecOpts {
|
||||||
return func(s *specs.Spec) error {
|
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
|
||||||
s.Process.Terminal = true
|
s.Process.Terminal = true
|
||||||
|
if s.Process.ConsoleSize == nil {
|
||||||
|
s.Process.ConsoleSize = &specs.Box{}
|
||||||
|
}
|
||||||
s.Process.ConsoleSize.Width = uint(width)
|
s.Process.ConsoleSize.Width = uint(width)
|
||||||
s.Process.ConsoleSize.Height = uint(height)
|
s.Process.ConsoleSize.Height = uint(height)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithSpec(spec *specs.Spec) NewContainerOpts {
|
|
||||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
|
||||||
any, err := typeurl.MarshalAny(spec)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Spec = any
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithResources(resources *specs.WindowsResources) UpdateTaskOpts {
|
func WithResources(resources *specs.WindowsResources) UpdateTaskOpts {
|
||||||
return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error {
|
return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error {
|
||||||
r.Resources = resources
|
r.Resources = resources
|
||||||
|
|
|
@ -25,7 +25,7 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func defaltCaps() []string {
|
func defaultCaps() []string {
|
||||||
return []string{
|
return []string{
|
||||||
"CAP_CHOWN",
|
"CAP_CHOWN",
|
||||||
"CAP_DAC_OVERRIDE",
|
"CAP_DAC_OVERRIDE",
|
||||||
|
@ -79,10 +79,10 @@ func createDefaultSpec() (*specs.Spec, error) {
|
||||||
GID: 0,
|
GID: 0,
|
||||||
},
|
},
|
||||||
Capabilities: &specs.LinuxCapabilities{
|
Capabilities: &specs.LinuxCapabilities{
|
||||||
Bounding: defaltCaps(),
|
Bounding: defaultCaps(),
|
||||||
Permitted: defaltCaps(),
|
Permitted: defaultCaps(),
|
||||||
Inheritable: defaltCaps(),
|
Inheritable: defaultCaps(),
|
||||||
Effective: defaltCaps(),
|
Effective: defaultCaps(),
|
||||||
},
|
},
|
||||||
Rlimits: []specs.POSIXRlimit{
|
Rlimits: []specs.POSIXRlimit{
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||||
"github.com/containerd/containerd/api/services/tasks/v1"
|
"github.com/containerd/containerd/api/services/tasks/v1"
|
||||||
|
@ -38,6 +39,8 @@ type Status struct {
|
||||||
Status ProcessStatus
|
Status ProcessStatus
|
||||||
// ExitStatus returned by the process
|
// ExitStatus returned by the process
|
||||||
ExitStatus uint32
|
ExitStatus uint32
|
||||||
|
// ExitedTime is the time at which the process died
|
||||||
|
ExitTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessStatus string
|
type ProcessStatus string
|
||||||
|
@ -113,13 +116,20 @@ type Task interface {
|
||||||
Checkpoint(context.Context, ...CheckpointTaskOpts) (v1.Descriptor, error)
|
Checkpoint(context.Context, ...CheckpointTaskOpts) (v1.Descriptor, error)
|
||||||
// Update modifies executing tasks with updated settings
|
// Update modifies executing tasks with updated settings
|
||||||
Update(context.Context, ...UpdateTaskOpts) error
|
Update(context.Context, ...UpdateTaskOpts) error
|
||||||
|
// LoadProcess loads a previously created exec'd process
|
||||||
|
LoadProcess(context.Context, string, IOAttach) (Process, error)
|
||||||
|
// Metrics returns task metrics for runtime specific metrics
|
||||||
|
//
|
||||||
|
// The metric types are generic to containerd and change depending on the runtime
|
||||||
|
// For the built in Linux runtime, github.com/containerd/cgroups.Metrics
|
||||||
|
// are returned in protobuf format
|
||||||
|
Metrics(context.Context) (*types.Metric, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = (Task)(&task{})
|
var _ = (Task)(&task{})
|
||||||
|
|
||||||
type task struct {
|
type task struct {
|
||||||
client *Client
|
client *Client
|
||||||
container Container
|
|
||||||
|
|
||||||
io IO
|
io IO
|
||||||
id string
|
id string
|
||||||
|
@ -159,10 +169,17 @@ func (t *task) Start(ctx context.Context) error {
|
||||||
return errdefs.FromGRPC(err)
|
return errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *task) Kill(ctx context.Context, s syscall.Signal) error {
|
func (t *task) Kill(ctx context.Context, s syscall.Signal, opts ...KillOpts) error {
|
||||||
|
var i KillInfo
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(ctx, t, &i); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
_, err := t.client.TaskService().Kill(ctx, &tasks.KillRequest{
|
_, err := t.client.TaskService().Kill(ctx, &tasks.KillRequest{
|
||||||
Signal: uint32(s),
|
Signal: uint32(s),
|
||||||
ContainerID: t.id,
|
ContainerID: t.id,
|
||||||
|
All: i.All,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errdefs.FromGRPC(err)
|
return errdefs.FromGRPC(err)
|
||||||
|
@ -194,18 +211,22 @@ func (t *task) Status(ctx context.Context) (Status, error) {
|
||||||
return Status{
|
return Status{
|
||||||
Status: ProcessStatus(strings.ToLower(r.Process.Status.String())),
|
Status: ProcessStatus(strings.ToLower(r.Process.Status.String())),
|
||||||
ExitStatus: r.Process.ExitStatus,
|
ExitStatus: r.Process.ExitStatus,
|
||||||
|
ExitTime: r.Process.ExitedAt,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *task) Wait(ctx context.Context) (uint32, error) {
|
func (t *task) Wait(ctx context.Context) (<-chan ExitStatus, error) {
|
||||||
cancellable, cancel := context.WithCancel(ctx)
|
cancellable, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
|
||||||
eventstream, err := t.client.EventService().Subscribe(cancellable, &eventsapi.SubscribeRequest{
|
eventstream, err := t.client.EventService().Subscribe(cancellable, &eventsapi.SubscribeRequest{
|
||||||
Filters: []string{"topic==" + runtime.TaskExitEventTopic},
|
Filters: []string{"topic==" + runtime.TaskExitEventTopic},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, errdefs.FromGRPC(err)
|
cancel()
|
||||||
|
return nil, errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chStatus := make(chan ExitStatus, 1)
|
||||||
|
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
checkpoint := t.deferred != nil
|
checkpoint := t.deferred != nil
|
||||||
t.mu.Unlock()
|
t.mu.Unlock()
|
||||||
|
@ -213,42 +234,56 @@ func (t *task) Wait(ctx context.Context) (uint32, error) {
|
||||||
// first check if the task has exited
|
// first check if the task has exited
|
||||||
status, err := t.Status(ctx)
|
status, err := t.Status(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, errdefs.FromGRPC(err)
|
cancel()
|
||||||
|
return nil, errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
if status.Status == Stopped {
|
if status.Status == Stopped {
|
||||||
return status.ExitStatus, nil
|
cancel()
|
||||||
|
chStatus <- ExitStatus{code: status.ExitStatus, exitedAt: status.ExitTime}
|
||||||
|
return chStatus, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer cancel()
|
||||||
|
chStatus <- ExitStatus{} // signal that goroutine is running
|
||||||
for {
|
for {
|
||||||
evt, err := eventstream.Recv()
|
evt, err := eventstream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, errdefs.FromGRPC(err)
|
chStatus <- ExitStatus{code: UnknownExitStatus, err: errdefs.FromGRPC(err)}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) {
|
if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) {
|
||||||
v, err := typeurl.UnmarshalAny(evt.Event)
|
v, err := typeurl.UnmarshalAny(evt.Event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, err
|
chStatus <- ExitStatus{code: UnknownExitStatus, err: err}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
e := v.(*eventsapi.TaskExit)
|
e := v.(*eventsapi.TaskExit)
|
||||||
if e.ContainerID == t.id && e.Pid == t.pid {
|
if e.ContainerID == t.id && e.Pid == t.pid {
|
||||||
return e.ExitStatus, nil
|
chStatus <- ExitStatus{code: e.ExitStatus, exitedAt: e.ExitedAt}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-chStatus // wait for the goroutine to be running
|
||||||
|
return chStatus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete deletes the task and its runtime state
|
// Delete deletes the task and its runtime state
|
||||||
// it returns the exit status of the task and any errors that were encountered
|
// it returns the exit status of the task and any errors that were encountered
|
||||||
// during cleanup
|
// during cleanup
|
||||||
func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, error) {
|
func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStatus, error) {
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
if err := o(ctx, t); err != nil {
|
if err := o(ctx, t); err != nil {
|
||||||
return UnknownExitStatus, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status, err := t.Status(ctx)
|
status, err := t.Status(ctx)
|
||||||
if err != nil && errdefs.IsNotFound(err) {
|
if err != nil && errdefs.IsNotFound(err) {
|
||||||
return UnknownExitStatus, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch status.Status {
|
switch status.Status {
|
||||||
case Stopped, Unknown, "":
|
case Stopped, Unknown, "":
|
||||||
|
@ -259,7 +294,7 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, e
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
return UnknownExitStatus, errors.Wrapf(errdefs.ErrFailedPrecondition, "task must be stopped before deletion: %s", status.Status)
|
return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "task must be stopped before deletion: %s", status.Status)
|
||||||
}
|
}
|
||||||
if t.io != nil {
|
if t.io != nil {
|
||||||
t.io.Cancel()
|
t.io.Cancel()
|
||||||
|
@ -270,9 +305,9 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (uint32, e
|
||||||
ContainerID: t.id,
|
ContainerID: t.id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UnknownExitStatus, errdefs.FromGRPC(err)
|
return nil, errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
return r.ExitStatus, nil
|
return &ExitStatus{code: r.ExitStatus, exitedAt: r.ExitedAt}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreate IOCreation) (Process, error) {
|
func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreate IOCreation) (Process, error) {
|
||||||
|
@ -307,7 +342,6 @@ func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreat
|
||||||
id: id,
|
id: id,
|
||||||
task: t,
|
task: t,
|
||||||
io: i,
|
io: i,
|
||||||
spec: spec,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +415,7 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (d v1
|
||||||
if err := t.checkpointImage(ctx, &index, cr.Image); err != nil {
|
if err := t.checkpointImage(ctx, &index, cr.Image); err != nil {
|
||||||
return d, err
|
return d, err
|
||||||
}
|
}
|
||||||
if err := t.checkpointRWSnapshot(ctx, &index, cr.Snapshotter, cr.RootFS); err != nil {
|
if err := t.checkpointRWSnapshot(ctx, &index, cr.Snapshotter, cr.SnapshotKey); err != nil {
|
||||||
return d, err
|
return d, err
|
||||||
}
|
}
|
||||||
index.Annotations = make(map[string]string)
|
index.Annotations = make(map[string]string)
|
||||||
|
@ -419,6 +453,43 @@ func (t *task) Update(ctx context.Context, opts ...UpdateTaskOpts) error {
|
||||||
return errdefs.FromGRPC(err)
|
return errdefs.FromGRPC(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *task) LoadProcess(ctx context.Context, id string, ioAttach IOAttach) (Process, error) {
|
||||||
|
response, err := t.client.TaskService().Get(ctx, &tasks.GetRequest{
|
||||||
|
ContainerID: t.id,
|
||||||
|
ExecID: id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
err = errdefs.FromGRPC(err)
|
||||||
|
if errdefs.IsNotFound(err) {
|
||||||
|
return nil, errors.Wrapf(err, "no running process found")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var i IO
|
||||||
|
if ioAttach != nil {
|
||||||
|
if i, err = attachExistingIO(response, ioAttach); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &process{
|
||||||
|
id: id,
|
||||||
|
task: t,
|
||||||
|
io: i,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *task) Metrics(ctx context.Context) (*types.Metric, error) {
|
||||||
|
response, err := t.client.TaskService().Metrics(ctx, &tasks.MetricsRequest{
|
||||||
|
Filters: []string{
|
||||||
|
"id==" + t.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errdefs.FromGRPC(err)
|
||||||
|
}
|
||||||
|
return response.Metrics[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tasks.CheckpointTaskRequest) error {
|
func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tasks.CheckpointTaskRequest) error {
|
||||||
response, err := t.client.TaskService().Checkpoint(ctx, request)
|
response, err := t.client.TaskService().Checkpoint(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -482,7 +553,7 @@ func writeContent(ctx context.Context, store content.Store, mediaType, ref strin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return d, err
|
return d, err
|
||||||
}
|
}
|
||||||
if err := writer.Commit(size, ""); err != nil {
|
if err := writer.Commit(ctx, size, ""); err != nil {
|
||||||
return d, err
|
return d, err
|
||||||
}
|
}
|
||||||
return v1.Descriptor{
|
return v1.Descriptor{
|
||||||
|
|
|
@ -33,16 +33,15 @@ type ProcessDeleteOpts func(context.Context, Process) error
|
||||||
|
|
||||||
// WithProcessKill will forcefully kill and delete a process
|
// WithProcessKill will forcefully kill and delete a process
|
||||||
func WithProcessKill(ctx context.Context, p Process) error {
|
func WithProcessKill(ctx context.Context, p Process) error {
|
||||||
s := make(chan struct{}, 1)
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
// ignore errors to wait and kill as we are forcefully killing
|
// ignore errors to wait and kill as we are forcefully killing
|
||||||
// the process and don't care about the exit status
|
// the process and don't care about the exit status
|
||||||
go func() {
|
s, err := p.Wait(ctx)
|
||||||
p.Wait(ctx)
|
if err != nil {
|
||||||
close(s)
|
return err
|
||||||
}()
|
}
|
||||||
if err := p.Kill(ctx, syscall.SIGKILL); err != nil {
|
if err := p.Kill(ctx, syscall.SIGKILL, WithKillAll); err != nil {
|
||||||
if errdefs.IsFailedPrecondition(err) || errdefs.IsNotFound(err) {
|
if errdefs.IsFailedPrecondition(err) || errdefs.IsNotFound(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -52,3 +51,17 @@ func WithProcessKill(ctx context.Context, p Process) error {
|
||||||
<-s
|
<-s
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KillInfo struct {
|
||||||
|
// All kills all processes inside the task
|
||||||
|
// only valid on tasks, ignored on processes
|
||||||
|
All bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type KillOpts func(context.Context, Process, *KillInfo) error
|
||||||
|
|
||||||
|
// WithKillAll kills all processes for a task
|
||||||
|
func WithKillAll(ctx context.Context, p Process, i *KillInfo) error {
|
||||||
|
i.All = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||||
github.com/containerd/go-runc b85ac701de5065a66918203dd18f057433290807
|
github.com/containerd/go-runc b3c048c028ddd789c6f9510c597f8b9c62f25359
|
||||||
github.com/containerd/console 76d18fd1d66972718ab2284449591db0b3cdb4de
|
github.com/containerd/console 76d18fd1d66972718ab2284449591db0b3cdb4de
|
||||||
github.com/containerd/cgroups 4fd64a776f25b5540cddcb72eea6e35e58baca6e
|
github.com/containerd/cgroups 5933ab4dc4f7caa3a73a1dc141bd11f42b5c9163
|
||||||
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
|
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
|
||||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
|
github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
|
||||||
|
@ -15,7 +15,7 @@ github.com/docker/go-units v0.3.1
|
||||||
github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8
|
github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8
|
||||||
github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55
|
github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55
|
||||||
github.com/opencontainers/runtime-spec v1.0.0
|
github.com/opencontainers/runtime-spec v1.0.0
|
||||||
github.com/opencontainers/runc e775f0fba3ea329b8b766451c892c41a3d49594d
|
github.com/opencontainers/runc 593914b8bd5448a93f7c3e4902a03408b6d5c0ce
|
||||||
github.com/sirupsen/logrus v1.0.0
|
github.com/sirupsen/logrus v1.0.0
|
||||||
github.com/containerd/btrfs cc52c4dea2ce11a44e6639e561bb5c2af9ada9e3
|
github.com/containerd/btrfs cc52c4dea2ce11a44e6639e561bb5c2af9ada9e3
|
||||||
github.com/stretchr/testify v1.1.4
|
github.com/stretchr/testify v1.1.4
|
||||||
|
@ -27,15 +27,16 @@ golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
|
||||||
google.golang.org/grpc v1.3.0
|
google.golang.org/grpc v1.3.0
|
||||||
github.com/pkg/errors v0.8.0
|
github.com/pkg/errors v0.8.0
|
||||||
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
|
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
|
||||||
golang.org/x/sys b892924b68aa53038e8a55b255ee0d8391e8eec5 https://github.com/golang/sys
|
golang.org/x/sys 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce https://github.com/golang/sys
|
||||||
github.com/opencontainers/image-spec v1.0.0
|
github.com/opencontainers/image-spec v1.0.0
|
||||||
github.com/containerd/continuity cf279e6ac893682272b4479d4c67fd3abf878b4e
|
github.com/containerd/continuity cf279e6ac893682272b4479d4c67fd3abf878b4e
|
||||||
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
||||||
github.com/BurntSushi/toml v0.2.0-21-g9906417
|
github.com/BurntSushi/toml v0.2.0-21-g9906417
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
||||||
github.com/Microsoft/go-winio v0.4.4
|
github.com/Microsoft/go-winio v0.4.4
|
||||||
|
github.com/Microsoft/hcsshim v0.6.3
|
||||||
|
github.com/Microsoft/opengcs v0.3.2
|
||||||
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
|
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
|
||||||
github.com/Microsoft/hcsshim v0.6.1
|
|
||||||
github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
|
github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
|
||||||
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||||
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
||||||
|
|
111
vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go
generated
vendored
Normal file
111
vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// The current operating system does not provide the required data for user lookups.
|
||||||
|
ErrUnsupported = errors.New("user lookup: operating system does not provide passwd-formatted data")
|
||||||
|
// No matching entries found in file.
|
||||||
|
ErrNoPasswdEntries = errors.New("no matching entries in passwd file")
|
||||||
|
ErrNoGroupEntries = errors.New("no matching entries in group file")
|
||||||
|
)
|
||||||
|
|
||||||
|
func lookupUser(filter func(u User) bool) (User, error) {
|
||||||
|
// Get operating system-specific passwd reader-closer.
|
||||||
|
passwd, err := GetPasswd()
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
defer passwd.Close()
|
||||||
|
|
||||||
|
// Get the users.
|
||||||
|
users, err := ParsePasswdFilter(passwd, filter)
|
||||||
|
if err != nil {
|
||||||
|
return User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No user entries found.
|
||||||
|
if len(users) == 0 {
|
||||||
|
return User{}, ErrNoPasswdEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the first entry is the "correct" one.
|
||||||
|
return users[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentUser looks up the current user by their user id in /etc/passwd. If the
|
||||||
|
// user cannot be found (or there is no /etc/passwd file on the filesystem),
|
||||||
|
// then CurrentUser returns an error.
|
||||||
|
func CurrentUser() (User, error) {
|
||||||
|
return LookupUid(unix.Getuid())
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupUser looks up a user by their username in /etc/passwd. If the user
|
||||||
|
// cannot be found (or there is no /etc/passwd file on the filesystem), then
|
||||||
|
// LookupUser returns an error.
|
||||||
|
func LookupUser(username string) (User, error) {
|
||||||
|
return lookupUser(func(u User) bool {
|
||||||
|
return u.Name == username
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
|
||||||
|
// be found (or there is no /etc/passwd file on the filesystem), then LookupId
|
||||||
|
// returns an error.
|
||||||
|
func LookupUid(uid int) (User, error) {
|
||||||
|
return lookupUser(func(u User) bool {
|
||||||
|
return u.Uid == uid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupGroup(filter func(g Group) bool) (Group, error) {
|
||||||
|
// Get operating system-specific group reader-closer.
|
||||||
|
group, err := GetGroup()
|
||||||
|
if err != nil {
|
||||||
|
return Group{}, err
|
||||||
|
}
|
||||||
|
defer group.Close()
|
||||||
|
|
||||||
|
// Get the users.
|
||||||
|
groups, err := ParseGroupFilter(group, filter)
|
||||||
|
if err != nil {
|
||||||
|
return Group{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No user entries found.
|
||||||
|
if len(groups) == 0 {
|
||||||
|
return Group{}, ErrNoGroupEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the first entry is the "correct" one.
|
||||||
|
return groups[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentGroup looks up the current user's group by their primary group id's
|
||||||
|
// entry in /etc/passwd. If the group cannot be found (or there is no
|
||||||
|
// /etc/group file on the filesystem), then CurrentGroup returns an error.
|
||||||
|
func CurrentGroup() (Group, error) {
|
||||||
|
return LookupGid(unix.Getgid())
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupGroup looks up a group by its name in /etc/group. If the group cannot
|
||||||
|
// be found (or there is no /etc/group file on the filesystem), then LookupGroup
|
||||||
|
// returns an error.
|
||||||
|
func LookupGroup(groupname string) (Group, error) {
|
||||||
|
return lookupGroup(func(g Group) bool {
|
||||||
|
return g.Name == groupname
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupGid looks up a group by its group id in /etc/group. If the group cannot
|
||||||
|
// be found (or there is no /etc/group file on the filesystem), then LookupGid
|
||||||
|
// returns an error.
|
||||||
|
func LookupGid(gid int) (Group, error) {
|
||||||
|
return lookupGroup(func(g Group) bool {
|
||||||
|
return g.Gid == gid
|
||||||
|
})
|
||||||
|
}
|
30
vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go
generated
vendored
Normal file
30
vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||||
|
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unix-specific path to the passwd and group formatted files.
|
||||||
|
const (
|
||||||
|
unixPasswdPath = "/etc/passwd"
|
||||||
|
unixGroupPath = "/etc/group"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetPasswdPath() (string, error) {
|
||||||
|
return unixPasswdPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPasswd() (io.ReadCloser, error) {
|
||||||
|
return os.Open(unixPasswdPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupPath() (string, error) {
|
||||||
|
return unixGroupPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroup() (io.ReadCloser, error) {
|
||||||
|
return os.Open(unixGroupPath)
|
||||||
|
}
|
21
vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go
generated
vendored
Normal file
21
vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||||
|
|
||||||
|
package user
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
func GetPasswdPath() (string, error) {
|
||||||
|
return "", ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPasswd() (io.ReadCloser, error) {
|
||||||
|
return nil, ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupPath() (string, error) {
|
||||||
|
return "", ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroup() (io.ReadCloser, error) {
|
||||||
|
return nil, ErrUnsupported
|
||||||
|
}
|
|
@ -0,0 +1,441 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minId = 0
|
||||||
|
maxId = 1<<31 - 1 //for 32-bit systems compatibility
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minId, maxId)
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string
|
||||||
|
Pass string
|
||||||
|
Uid int
|
||||||
|
Gid int
|
||||||
|
Gecos string
|
||||||
|
Home string
|
||||||
|
Shell string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Group struct {
|
||||||
|
Name string
|
||||||
|
Pass string
|
||||||
|
Gid int
|
||||||
|
List []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLine(line string, v ...interface{}) {
|
||||||
|
if line == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
for i, p := range parts {
|
||||||
|
// Ignore cases where we don't have enough fields to populate the arguments.
|
||||||
|
// Some configuration files like to misbehave.
|
||||||
|
if len(v) <= i {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the type of the argument to figure out how to parse it, scanf() style.
|
||||||
|
// This is legit.
|
||||||
|
switch e := v[i].(type) {
|
||||||
|
case *string:
|
||||||
|
*e = p
|
||||||
|
case *int:
|
||||||
|
// "numbers", with conversion errors ignored because of some misbehaving configuration files.
|
||||||
|
*e, _ = strconv.Atoi(p)
|
||||||
|
case *[]string:
|
||||||
|
// Comma-separated lists.
|
||||||
|
if p != "" {
|
||||||
|
*e = strings.Split(p, ",")
|
||||||
|
} else {
|
||||||
|
*e = []string{}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Someone goof'd when writing code using this function. Scream so they can hear us.
|
||||||
|
panic(fmt.Sprintf("parseLine only accepts {*string, *int, *[]string} as arguments! %#v is not a pointer!", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParsePasswdFile(path string) ([]User, error) {
|
||||||
|
passwd, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer passwd.Close()
|
||||||
|
return ParsePasswd(passwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParsePasswd(passwd io.Reader) ([]User, error) {
|
||||||
|
return ParsePasswdFilter(passwd, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParsePasswdFileFilter(path string, filter func(User) bool) ([]User, error) {
|
||||||
|
passwd, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer passwd.Close()
|
||||||
|
return ParsePasswdFilter(passwd, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) {
|
||||||
|
if r == nil {
|
||||||
|
return nil, fmt.Errorf("nil source for passwd-formatted data")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
s = bufio.NewScanner(r)
|
||||||
|
out = []User{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for s.Scan() {
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
line := strings.TrimSpace(s.Text())
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// see: man 5 passwd
|
||||||
|
// name:password:UID:GID:GECOS:directory:shell
|
||||||
|
// Name:Pass:Uid:Gid:Gecos:Home:Shell
|
||||||
|
// root:x:0:0:root:/root:/bin/bash
|
||||||
|
// adm:x:3:4:adm:/var/adm:/bin/false
|
||||||
|
p := User{}
|
||||||
|
parseLine(line, &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell)
|
||||||
|
|
||||||
|
if filter == nil || filter(p) {
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseGroupFile(path string) ([]Group, error) {
|
||||||
|
group, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer group.Close()
|
||||||
|
return ParseGroup(group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseGroup(group io.Reader) ([]Group, error) {
|
||||||
|
return ParseGroupFilter(group, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseGroupFileFilter(path string, filter func(Group) bool) ([]Group, error) {
|
||||||
|
group, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer group.Close()
|
||||||
|
return ParseGroupFilter(group, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) {
|
||||||
|
if r == nil {
|
||||||
|
return nil, fmt.Errorf("nil source for group-formatted data")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
s = bufio.NewScanner(r)
|
||||||
|
out = []Group{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for s.Scan() {
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
text := s.Text()
|
||||||
|
if text == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// see: man 5 group
|
||||||
|
// group_name:password:GID:user_list
|
||||||
|
// Name:Pass:Gid:List
|
||||||
|
// root:x:0:root
|
||||||
|
// adm:x:4:root,adm,daemon
|
||||||
|
p := Group{}
|
||||||
|
parseLine(text, &p.Name, &p.Pass, &p.Gid, &p.List)
|
||||||
|
|
||||||
|
if filter == nil || filter(p) {
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecUser struct {
|
||||||
|
Uid int
|
||||||
|
Gid int
|
||||||
|
Sgids []int
|
||||||
|
Home string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExecUserPath is a wrapper for GetExecUser. It reads data from each of the
|
||||||
|
// given file paths and uses that data as the arguments to GetExecUser. If the
|
||||||
|
// files cannot be opened for any reason, the error is ignored and a nil
|
||||||
|
// io.Reader is passed instead.
|
||||||
|
func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
|
||||||
|
var passwd, group io.Reader
|
||||||
|
|
||||||
|
if passwdFile, err := os.Open(passwdPath); err == nil {
|
||||||
|
passwd = passwdFile
|
||||||
|
defer passwdFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if groupFile, err := os.Open(groupPath); err == nil {
|
||||||
|
group = groupFile
|
||||||
|
defer groupFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetExecUser(userSpec, defaults, passwd, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExecUser parses a user specification string (using the passwd and group
|
||||||
|
// readers as sources for /etc/passwd and /etc/group data, respectively). In
|
||||||
|
// the case of blank fields or missing data from the sources, the values in
|
||||||
|
// defaults is used.
|
||||||
|
//
|
||||||
|
// GetExecUser will return an error if a user or group literal could not be
|
||||||
|
// found in any entry in passwd and group respectively.
|
||||||
|
//
|
||||||
|
// Examples of valid user specifications are:
|
||||||
|
// * ""
|
||||||
|
// * "user"
|
||||||
|
// * "uid"
|
||||||
|
// * "user:group"
|
||||||
|
// * "uid:gid
|
||||||
|
// * "user:gid"
|
||||||
|
// * "uid:group"
|
||||||
|
//
|
||||||
|
// It should be noted that if you specify a numeric user or group id, they will
|
||||||
|
// not be evaluated as usernames (only the metadata will be filled). So attempting
|
||||||
|
// to parse a user with user.Name = "1337" will produce the user with a UID of
|
||||||
|
// 1337.
|
||||||
|
func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (*ExecUser, error) {
|
||||||
|
if defaults == nil {
|
||||||
|
defaults = new(ExecUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy over defaults.
|
||||||
|
user := &ExecUser{
|
||||||
|
Uid: defaults.Uid,
|
||||||
|
Gid: defaults.Gid,
|
||||||
|
Sgids: defaults.Sgids,
|
||||||
|
Home: defaults.Home,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sgids slice *cannot* be nil.
|
||||||
|
if user.Sgids == nil {
|
||||||
|
user.Sgids = []int{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow for userArg to have either "user" syntax, or optionally "user:group" syntax
|
||||||
|
var userArg, groupArg string
|
||||||
|
parseLine(userSpec, &userArg, &groupArg)
|
||||||
|
|
||||||
|
// Convert userArg and groupArg to be numeric, so we don't have to execute
|
||||||
|
// Atoi *twice* for each iteration over lines.
|
||||||
|
uidArg, uidErr := strconv.Atoi(userArg)
|
||||||
|
gidArg, gidErr := strconv.Atoi(groupArg)
|
||||||
|
|
||||||
|
// Find the matching user.
|
||||||
|
users, err := ParsePasswdFilter(passwd, func(u User) bool {
|
||||||
|
if userArg == "" {
|
||||||
|
// Default to current state of the user.
|
||||||
|
return u.Uid == user.Uid
|
||||||
|
}
|
||||||
|
|
||||||
|
if uidErr == nil {
|
||||||
|
// If the userArg is numeric, always treat it as a UID.
|
||||||
|
return uidArg == u.Uid
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.Name == userArg
|
||||||
|
})
|
||||||
|
|
||||||
|
// If we can't find the user, we have to bail.
|
||||||
|
if err != nil && passwd != nil {
|
||||||
|
if userArg == "" {
|
||||||
|
userArg = strconv.Itoa(user.Uid)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to find user %s: %v", userArg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchedUserName string
|
||||||
|
if len(users) > 0 {
|
||||||
|
// First match wins, even if there's more than one matching entry.
|
||||||
|
matchedUserName = users[0].Name
|
||||||
|
user.Uid = users[0].Uid
|
||||||
|
user.Gid = users[0].Gid
|
||||||
|
user.Home = users[0].Home
|
||||||
|
} else if userArg != "" {
|
||||||
|
// If we can't find a user with the given username, the only other valid
|
||||||
|
// option is if it's a numeric username with no associated entry in passwd.
|
||||||
|
|
||||||
|
if uidErr != nil {
|
||||||
|
// Not numeric.
|
||||||
|
return nil, fmt.Errorf("unable to find user %s: %v", userArg, ErrNoPasswdEntries)
|
||||||
|
}
|
||||||
|
user.Uid = uidArg
|
||||||
|
|
||||||
|
// Must be inside valid uid range.
|
||||||
|
if user.Uid < minId || user.Uid > maxId {
|
||||||
|
return nil, ErrRange
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, so it's numeric. We can just roll with this.
|
||||||
|
}
|
||||||
|
|
||||||
|
// On to the groups. If we matched a username, we need to do this because of
|
||||||
|
// the supplementary group IDs.
|
||||||
|
if groupArg != "" || matchedUserName != "" {
|
||||||
|
groups, err := ParseGroupFilter(group, func(g Group) bool {
|
||||||
|
// If the group argument isn't explicit, we'll just search for it.
|
||||||
|
if groupArg == "" {
|
||||||
|
// Check if user is a member of this group.
|
||||||
|
for _, u := range g.List {
|
||||||
|
if u == matchedUserName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if gidErr == nil {
|
||||||
|
// If the groupArg is numeric, always treat it as a GID.
|
||||||
|
return gidArg == g.Gid
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.Name == groupArg
|
||||||
|
})
|
||||||
|
if err != nil && group != nil {
|
||||||
|
return nil, fmt.Errorf("unable to find groups for spec %v: %v", matchedUserName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only start modifying user.Gid if it is in explicit form.
|
||||||
|
if groupArg != "" {
|
||||||
|
if len(groups) > 0 {
|
||||||
|
// First match wins, even if there's more than one matching entry.
|
||||||
|
user.Gid = groups[0].Gid
|
||||||
|
} else {
|
||||||
|
// If we can't find a group with the given name, the only other valid
|
||||||
|
// option is if it's a numeric group name with no associated entry in group.
|
||||||
|
|
||||||
|
if gidErr != nil {
|
||||||
|
// Not numeric.
|
||||||
|
return nil, fmt.Errorf("unable to find group %s: %v", groupArg, ErrNoGroupEntries)
|
||||||
|
}
|
||||||
|
user.Gid = gidArg
|
||||||
|
|
||||||
|
// Must be inside valid gid range.
|
||||||
|
if user.Gid < minId || user.Gid > maxId {
|
||||||
|
return nil, ErrRange
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, so it's numeric. We can just roll with this.
|
||||||
|
}
|
||||||
|
} else if len(groups) > 0 && uidErr != nil {
|
||||||
|
// Supplementary group ids only make sense if in the implicit form for non-numeric users.
|
||||||
|
user.Sgids = make([]int, len(groups))
|
||||||
|
for i, group := range groups {
|
||||||
|
user.Sgids[i] = group.Gid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAdditionalGroups looks up a list of groups by name or group id
|
||||||
|
// against the given /etc/group formatted data. If a group name cannot
|
||||||
|
// be found, an error will be returned. If a group id cannot be found,
|
||||||
|
// or the given group data is nil, the id will be returned as-is
|
||||||
|
// provided it is in the legal range.
|
||||||
|
func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, error) {
|
||||||
|
var groups = []Group{}
|
||||||
|
if group != nil {
|
||||||
|
var err error
|
||||||
|
groups, err = ParseGroupFilter(group, func(g Group) bool {
|
||||||
|
for _, ag := range additionalGroups {
|
||||||
|
if g.Name == ag || strconv.Itoa(g.Gid) == ag {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gidMap := make(map[int]struct{})
|
||||||
|
for _, ag := range additionalGroups {
|
||||||
|
var found bool
|
||||||
|
for _, g := range groups {
|
||||||
|
// if we found a matched group either by name or gid, take the
|
||||||
|
// first matched as correct
|
||||||
|
if g.Name == ag || strconv.Itoa(g.Gid) == ag {
|
||||||
|
if _, ok := gidMap[g.Gid]; !ok {
|
||||||
|
gidMap[g.Gid] = struct{}{}
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we asked for a group but didn't find it. let's check to see
|
||||||
|
// if we wanted a numeric group
|
||||||
|
if !found {
|
||||||
|
gid, err := strconv.Atoi(ag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to find group %s", ag)
|
||||||
|
}
|
||||||
|
// Ensure gid is inside gid range.
|
||||||
|
if gid < minId || gid > maxId {
|
||||||
|
return nil, ErrRange
|
||||||
|
}
|
||||||
|
gidMap[gid] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gids := []int{}
|
||||||
|
for gid := range gidMap {
|
||||||
|
gids = append(gids, gid)
|
||||||
|
}
|
||||||
|
return gids, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAdditionalGroupsPath is a wrapper around GetAdditionalGroups
|
||||||
|
// that opens the groupPath given and gives it as an argument to
|
||||||
|
// GetAdditionalGroups.
|
||||||
|
func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) {
|
||||||
|
var group io.Reader
|
||||||
|
|
||||||
|
if groupFile, err := os.Open(groupPath); err == nil {
|
||||||
|
group = groupFile
|
||||||
|
defer groupFile.Close()
|
||||||
|
}
|
||||||
|
return GetAdditionalGroups(additionalGroups, group)
|
||||||
|
}
|
|
@ -58,12 +58,13 @@ func (w containerdWorker) Exec(ctx context.Context, meta worker.Meta, root cache
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
status, err := task.Wait(ctx)
|
statusCh, err := task.Wait(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if status != 0 {
|
status := <-statusCh
|
||||||
return errors.Errorf("process returned non-zero status: %d", status)
|
if status.ExitCode() != 0 {
|
||||||
|
return errors.Errorf("process returned non-zero exit code: %d", status.ExitCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
// Ideally we don't have to import whole containerd just for the default spec
|
// Ideally we don't have to import whole containerd just for the default spec
|
||||||
|
|
||||||
func GenerateSpec(ctx context.Context, meta worker.Meta, mounts []worker.Mount) (*specs.Spec, func(), error) {
|
func GenerateSpec(ctx context.Context, meta worker.Meta, mounts []worker.Mount) (*specs.Spec, func(), error) {
|
||||||
s, err := containerd.GenerateSpec(
|
s, err := containerd.GenerateSpec(ctx, nil, nil,
|
||||||
containerd.WithHostNamespace(specs.NetworkNamespace),
|
containerd.WithHostNamespace(specs.NetworkNamespace),
|
||||||
containerd.WithHostResolvconf,
|
containerd.WithHostResolvconf,
|
||||||
containerd.WithHostHostsFile,
|
containerd.WithHostHostsFile,
|
||||||
|
|
Loading…
Reference in New Issue