Updating to container1.0-alpha

Signed-off-by: Abhinandan Prativadi <abhi@docker.com>
This commit is contained in:
Abhinandan Prativadi 2017-08-23 18:05:15 -07:00
parent 07e3a2b5e2
commit 728dced6a1
41 changed files with 886 additions and 317 deletions

View File

@ -1,5 +1,5 @@
RUNC_VERSION=e775f0fba3ea329b8b766451c892c41a3d49594d RUNC_VERSION=e775f0fba3ea329b8b766451c892c41a3d49594d
CNI_VERSION=v0.6.0 CNI_VERSION=v0.6.0
CONTAINERD_VERSION=938810e706bbcdbcb937ce63ba3e7c9ca329af64 CONTAINERD_VERSION=f05281743e5ac9ad11c6e19a72be7a903eab79f5
CRITEST_VERSION=74bbd4e142f752f13c648d9dde23defed3e472a2 CRITEST_VERSION=74bbd4e142f752f13c648d9dde23defed3e472a2
KUBERNETES_VERSION=493ee8b28560c118cebd2165ba9ef0959cfa2bc3 KUBERNETES_VERSION=493ee8b28560c118cebd2165ba9ef0959cfa2bc3

View File

@ -72,12 +72,6 @@ type execOptions struct {
timeout time.Duration timeout time.Duration
} }
// execResult is the result returned by exec.
type execResult struct {
exitCode uint32
err error
}
// execInContainer executes a command inside the container synchronously, and // execInContainer executes a command inside the container synchronously, and
// redirects stdio stream properly. // redirects stdio stream properly.
func (c *criContainerdService) execInContainer(ctx context.Context, id string, opts execOptions) (*uint32, error) { func (c *criContainerdService) execInContainer(ctx context.Context, id string, opts execOptions) (*uint32, error) {
@ -127,8 +121,6 @@ func (c *criContainerdService) execInContainer(ctx context.Context, id string, o
return nil, fmt.Errorf("failed to create exec %q: %v", execID, err) return nil, fmt.Errorf("failed to create exec %q: %v", execID, err)
} }
defer func() { defer func() {
// TODO(random-liu): There is a containerd bug here containerd#1376, revisit this
// after that is fixed.
if _, err := process.Delete(ctx); err != nil { if _, err := process.Delete(ctx); err != nil {
glog.Errorf("Failed to delete exec process %q for container %q: %v", execID, id, err) glog.Errorf("Failed to delete exec process %q for container %q: %v", execID, id, err)
} }
@ -140,16 +132,10 @@ func (c *criContainerdService) execInContainer(ctx context.Context, id string, o
} }
}) })
resCh := make(chan execResult, 1) exitCh, err := process.Wait(ctx)
go func() { if err != nil {
// Wait will return if context is cancelled. return nil, fmt.Errorf("failed to wait for process %q: %v", execID, err)
exitCode, err := process.Wait(ctx) }
resCh <- execResult{
exitCode: exitCode,
err: err,
}
glog.V(2).Infof("Exec process %q exits with exit code %d and error %v", execID, exitCode, err)
}()
if err := process.Start(ctx); err != nil { if err := process.Start(ctx); err != nil {
return nil, fmt.Errorf("failed to start exec %q: %v", execID, err) return nil, fmt.Errorf("failed to start exec %q: %v", execID, err)
} }
@ -163,17 +149,22 @@ func (c *criContainerdService) execInContainer(ctx context.Context, id string, o
} }
select { select {
case <-timeoutCh: case <-timeoutCh:
//TODO(Abhi) Use context.WithDeadline instead of timeout.
// Ignore the not found error because the process may exit itself before killing. // Ignore the not found error because the process may exit itself before killing.
if err := process.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) { if err := process.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) {
return nil, fmt.Errorf("failed to kill exec %q: %v", execID, err) return nil, fmt.Errorf("failed to kill exec %q: %v", execID, err)
} }
// Wait for the process to be killed. // Wait for the process to be killed.
<-resCh exitRes := <-exitCh
glog.V(2).Infof("Timeout received while waiting for exec process kill %q code %d and error %v",
execID, exitRes.ExitCode(), exitRes.Error())
return nil, fmt.Errorf("timeout %v exceeded", opts.timeout) return nil, fmt.Errorf("timeout %v exceeded", opts.timeout)
case res := <-resCh: case exitRes := <-exitCh:
if res.err != nil { code, _, err := exitRes.Result()
return nil, fmt.Errorf("failed to wait for exec %q: %v", execID, res.err) glog.V(2).Infof("Exec process %q exits with exit code %d and error %v", execID, code, err)
if err != nil {
return nil, fmt.Errorf("failed while waiting for exec %q: %v", execID, err)
} }
return &res.exitCode, nil return &code, nil
} }
} }

View File

@ -1,6 +1,6 @@
github.com/blang/semver v3.1.0 github.com/blang/semver v3.1.0
github.com/boltdb/bolt v1.3.0-58-ge9cf4fa github.com/boltdb/bolt v1.3.0-58-ge9cf4fa
github.com/containerd/containerd f79981c2dfe35c3bfcbdd2de9b682e8c3de904b2 github.com/containerd/containerd f05281743e5ac9ad11c6e19a72be7a903eab79f5
github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6 github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6
github.com/containernetworking/cni v0.6.0 github.com/containernetworking/cni v0.6.0
github.com/cri-o/ocicni 0f90d35d89e9ab7e972a9edeb36b0aaffa250335 github.com/cri-o/ocicni 0f90d35d89e9ab7e972a9edeb36b0aaffa250335

View File

@ -321,6 +321,8 @@ type WriteContentRequest struct {
// If this is empty and the message is not a commit, a response will be // If this is empty and the message is not a commit, a response will be
// returned with the current write state. // returned with the current write state.
Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
// Labels are arbitrary data to set on commit.
Labels map[string]string `protobuf:"bytes,7,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
func (m *WriteContentRequest) Reset() { *m = WriteContentRequest{} } func (m *WriteContentRequest) Reset() { *m = WriteContentRequest{} }
@ -1445,6 +1447,23 @@ func (m *WriteContentRequest) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintContent(dAtA, i, uint64(len(m.Data))) i = encodeVarintContent(dAtA, i, uint64(len(m.Data)))
i += copy(dAtA[i:], m.Data) i += copy(dAtA[i:], m.Data)
} }
if len(m.Labels) > 0 {
for k, _ := range m.Labels {
dAtA[i] = 0x3a
i++
v := m.Labels[k]
mapSize := 1 + len(k) + sovContent(uint64(len(k))) + 1 + len(v) + sovContent(uint64(len(v)))
i = encodeVarintContent(dAtA, i, uint64(mapSize))
dAtA[i] = 0xa
i++
i = encodeVarintContent(dAtA, i, uint64(len(k)))
i += copy(dAtA[i:], k)
dAtA[i] = 0x12
i++
i = encodeVarintContent(dAtA, i, uint64(len(v)))
i += copy(dAtA[i:], v)
}
}
return i, nil return i, nil
} }
@ -1772,6 +1791,14 @@ func (m *WriteContentRequest) Size() (n int) {
if l > 0 { if l > 0 {
n += 1 + l + sovContent(uint64(l)) n += 1 + l + sovContent(uint64(l))
} }
if len(m.Labels) > 0 {
for k, v := range m.Labels {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovContent(uint64(len(k))) + 1 + len(v) + sovContent(uint64(len(v)))
n += mapEntrySize + 1 + sovContent(uint64(mapEntrySize))
}
}
return n return n
} }
@ -1998,6 +2025,16 @@ func (this *WriteContentRequest) String() string {
if this == nil { if this == nil {
return "nil" return "nil"
} }
keysForLabels := make([]string, 0, len(this.Labels))
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
}
mapStringForLabels += "}"
s := strings.Join([]string{`&WriteContentRequest{`, s := strings.Join([]string{`&WriteContentRequest{`,
`Action:` + fmt.Sprintf("%v", this.Action) + `,`, `Action:` + fmt.Sprintf("%v", this.Action) + `,`,
`Ref:` + fmt.Sprintf("%v", this.Ref) + `,`, `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
@ -2005,6 +2042,7 @@ func (this *WriteContentRequest) String() string {
`Expected:` + fmt.Sprintf("%v", this.Expected) + `,`, `Expected:` + fmt.Sprintf("%v", this.Expected) + `,`,
`Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
`Data:` + fmt.Sprintf("%v", this.Data) + `,`, `Data:` + fmt.Sprintf("%v", this.Data) + `,`,
`Labels:` + mapStringForLabels + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -3827,6 +3865,122 @@ func (m *WriteContentRequest) Unmarshal(dAtA []byte) error {
m.Data = []byte{} m.Data = []byte{}
} }
iNdEx = postIndex iNdEx = postIndex
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContent
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthContent
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
var keykey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContent
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
keykey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContent
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthContent
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
if m.Labels == nil {
m.Labels = make(map[string]string)
}
if iNdEx < postIndex {
var valuekey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContent
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
valuekey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowContent
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return ErrInvalidLengthContent
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
m.Labels[mapkey] = mapvalue
} else {
var mapvalue string
m.Labels[mapkey] = mapvalue
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipContent(dAtA[iNdEx:]) skippy, err := skipContent(dAtA[iNdEx:])
@ -4233,72 +4387,73 @@ func init() {
} }
var fileDescriptorContent = []byte{ var fileDescriptorContent = []byte{
// 1065 bytes of a gzipped FileDescriptorProto // 1079 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6f, 0x1b, 0x45,
0x14, 0xf7, 0x78, 0xed, 0x4d, 0xfc, 0x9c, 0x16, 0x33, 0x36, 0x95, 0xb5, 0x08, 0x7b, 0xbb, 0x42, 0x14, 0xcf, 0x78, 0xed, 0x4d, 0xf2, 0x9c, 0x16, 0x33, 0x31, 0x95, 0xb5, 0x08, 0x7b, 0xbb, 0x42,
0xc8, 0x6a, 0xc9, 0x3a, 0x75, 0x72, 0x00, 0x2a, 0x21, 0x1c, 0x37, 0x55, 0x83, 0x9a, 0x82, 0xb6, 0xc8, 0x6a, 0xc9, 0x3a, 0x75, 0x7a, 0x00, 0x2a, 0x01, 0x8e, 0x9b, 0xaa, 0x41, 0x4d, 0x41, 0x5b,
0x2e, 0x15, 0xbd, 0x94, 0xb5, 0x3d, 0x36, 0xab, 0xd8, 0x5e, 0x77, 0x77, 0x6c, 0x11, 0x4e, 0x5c, 0x97, 0x88, 0x5e, 0xca, 0xda, 0x1e, 0x9b, 0x55, 0x6c, 0xaf, 0xbb, 0x33, 0xb6, 0x08, 0x27, 0x2e,
0x90, 0x50, 0xd4, 0x03, 0x5f, 0x20, 0x17, 0xe0, 0x53, 0x70, 0xe0, 0x9c, 0x23, 0x47, 0xc4, 0xa1, 0x48, 0x28, 0xea, 0x01, 0x71, 0xcf, 0x05, 0xf8, 0x2b, 0x38, 0x70, 0xce, 0x91, 0x23, 0xe2, 0xd0,
0x25, 0xf9, 0x0e, 0x5c, 0x11, 0x9a, 0x3f, 0x6b, 0xaf, 0xed, 0x04, 0xff, 0x89, 0x39, 0xe5, 0xcd, 0xd2, 0xfc, 0x0f, 0xdc, 0xd1, 0xcc, 0xce, 0xda, 0xeb, 0x8f, 0xb0, 0xb6, 0xe3, 0x9e, 0xfc, 0x66,
0xf8, 0xfd, 0xde, 0xbc, 0xf7, 0x7b, 0xff, 0x36, 0x70, 0xbf, 0xe5, 0xd0, 0xaf, 0xfb, 0x35, 0xb3, 0xf6, 0xfd, 0xde, 0xf7, 0xc7, 0x18, 0xee, 0x35, 0x1d, 0xf6, 0x4d, 0xaf, 0x6a, 0xd6, 0xdc, 0x76,
0xee, 0x76, 0x8a, 0x75, 0xb7, 0x4b, 0x6d, 0xa7, 0x4b, 0xbc, 0x46, 0x58, 0xb4, 0x7b, 0x4e, 0xd1, 0xa1, 0xe6, 0x76, 0x98, 0xed, 0x74, 0x88, 0x57, 0x0f, 0x93, 0x76, 0xd7, 0x29, 0x50, 0xe2, 0xf5,
0x27, 0xde, 0xc0, 0xa9, 0x13, 0x9f, 0xdf, 0x93, 0x2e, 0x2d, 0x0e, 0xee, 0x04, 0xa2, 0xd9, 0xf3, 0x9d, 0x1a, 0xa1, 0xe2, 0x9e, 0x74, 0x58, 0xa1, 0x7f, 0x2b, 0x20, 0xcd, 0xae, 0xe7, 0x32, 0x17,
0x5c, 0xea, 0xe2, 0xdc, 0x08, 0x61, 0x06, 0xda, 0x66, 0xa0, 0x32, 0xb8, 0xa3, 0x65, 0x5a, 0x6e, 0x67, 0x87, 0x08, 0x33, 0xe0, 0x36, 0x03, 0x96, 0xfe, 0x2d, 0x2d, 0xdd, 0x74, 0x9b, 0xae, 0x60,
0xcb, 0xe5, 0xaa, 0x45, 0x26, 0x09, 0x94, 0xa6, 0xb7, 0x5c, 0xb7, 0xd5, 0x26, 0x45, 0x7e, 0xaa, 0x2d, 0x70, 0xca, 0x47, 0x69, 0x7a, 0xd3, 0x75, 0x9b, 0x2d, 0x52, 0x10, 0xa7, 0x6a, 0xaf, 0x51,
0xf5, 0x9b, 0xc5, 0xa6, 0x43, 0xda, 0x8d, 0xe7, 0x1d, 0xdb, 0x3f, 0x94, 0x1a, 0xf9, 0x49, 0x0d, 0x68, 0x38, 0xa4, 0x55, 0x7f, 0xda, 0xb6, 0xe9, 0x91, 0xe4, 0xc8, 0x8d, 0x73, 0x30, 0xa7, 0x4d,
0xea, 0x74, 0x88, 0x4f, 0xed, 0x4e, 0x4f, 0x2a, 0xbc, 0x3d, 0xa9, 0x40, 0x3a, 0x3d, 0x7a, 0x24, 0x28, 0xb3, 0xdb, 0x5d, 0xc9, 0xf0, 0xf6, 0x38, 0x03, 0x69, 0x77, 0xd9, 0xb1, 0xff, 0xd1, 0xf8,
0x7e, 0x34, 0xfe, 0x8e, 0x42, 0x6c, 0xbf, 0xdb, 0x74, 0xf1, 0xa7, 0xa0, 0x36, 0x9c, 0x16, 0xf1, 0x37, 0x06, 0xf1, 0xfd, 0x4e, 0xc3, 0xc5, 0x9f, 0x81, 0x5a, 0x77, 0x9a, 0x84, 0xb2, 0x0c, 0xd2,
0x69, 0x16, 0xe9, 0xa8, 0x90, 0xd8, 0x2d, 0x9d, 0xbe, 0xca, 0x47, 0xfe, 0x7c, 0x95, 0xbf, 0x15, 0x51, 0x7e, 0x7d, 0xb7, 0x78, 0xf6, 0x22, 0xb7, 0xf2, 0xf7, 0x8b, 0xdc, 0x8d, 0x90, 0xfb, 0x6e,
0x0a, 0xdf, 0xed, 0x91, 0xee, 0x30, 0x0a, 0xbf, 0xd8, 0x72, 0x37, 0x05, 0xc4, 0xbc, 0xc7, 0xff, 0x97, 0x74, 0x06, 0x5e, 0xd0, 0x42, 0xd3, 0xdd, 0xf2, 0x21, 0xe6, 0x5d, 0xf1, 0x63, 0x49, 0x09,
0x58, 0xd2, 0x02, 0xc6, 0x10, 0xf3, 0x9d, 0x6f, 0x49, 0x36, 0xaa, 0xa3, 0x82, 0x62, 0x71, 0x19, 0x18, 0x43, 0x9c, 0x3a, 0xdf, 0x91, 0x4c, 0x4c, 0x47, 0x79, 0xc5, 0x12, 0x34, 0x2e, 0x03, 0xd4,
0x57, 0x00, 0xea, 0x1e, 0xb1, 0x29, 0x69, 0x3c, 0xb7, 0x69, 0x56, 0xd1, 0x51, 0x21, 0x59, 0xd2, 0x3c, 0x62, 0x33, 0x52, 0x7f, 0x6a, 0xb3, 0x8c, 0xa2, 0xa3, 0x7c, 0xb2, 0xa8, 0x99, 0xbe, 0x69,
0x4c, 0xe1, 0x9a, 0x19, 0xb8, 0x66, 0x56, 0x03, 0xdf, 0x77, 0xd7, 0xd9, 0xfb, 0x3f, 0xbe, 0xce, 0x66, 0x60, 0x9a, 0x59, 0x09, 0x6c, 0xdf, 0x5d, 0xe3, 0xfa, 0x7f, 0x7a, 0x99, 0x43, 0xd6, 0xba,
0x23, 0x2b, 0x21, 0x71, 0x65, 0xca, 0x8c, 0xf4, 0x7b, 0x8d, 0xc0, 0x48, 0x6c, 0x11, 0x23, 0x12, 0xc4, 0x95, 0x18, 0x17, 0xd2, 0xeb, 0xd6, 0x03, 0x21, 0xf1, 0x79, 0x84, 0x48, 0x5c, 0x89, 0xe1,
0x57, 0xa6, 0xf8, 0x01, 0xa8, 0x6d, 0xbb, 0x46, 0xda, 0x7e, 0x36, 0xae, 0x2b, 0x85, 0x64, 0x69, 0xfb, 0xa0, 0xb6, 0xec, 0x2a, 0x69, 0xd1, 0x4c, 0x42, 0x57, 0xf2, 0xc9, 0xe2, 0xb6, 0xf9, 0xff,
0xcb, 0xfc, 0xef, 0xcc, 0x98, 0x8c, 0x1f, 0xf3, 0x21, 0x87, 0xec, 0x75, 0xa9, 0x77, 0x64, 0x49, 0x99, 0x31, 0x79, 0x7c, 0xcc, 0x07, 0x02, 0xb2, 0xd7, 0x61, 0xde, 0xb1, 0x25, 0xf1, 0xda, 0x87,
0xbc, 0xf6, 0x21, 0x24, 0x43, 0xd7, 0x38, 0x05, 0xca, 0x21, 0x39, 0x12, 0xfc, 0x59, 0x4c, 0xc4, 0x90, 0x0c, 0x5d, 0xe3, 0x14, 0x28, 0x47, 0xe4, 0xd8, 0x8f, 0x9f, 0xc5, 0x49, 0x9c, 0x86, 0x44,
0x19, 0x88, 0x0f, 0xec, 0x76, 0x5f, 0x30, 0x91, 0xb0, 0xc4, 0xe1, 0xa3, 0xe8, 0x07, 0xc8, 0xf8, 0xdf, 0x6e, 0xf5, 0xfc, 0x48, 0xac, 0x5b, 0xfe, 0xe1, 0xa3, 0xd8, 0x07, 0xc8, 0xf8, 0x0a, 0x92,
0x12, 0x92, 0xcc, 0xac, 0x45, 0x5e, 0xf4, 0x19, 0x63, 0x2b, 0x64, 0xdf, 0x78, 0x04, 0x1b, 0xc2, 0x5c, 0xac, 0x45, 0x9e, 0xf5, 0x78, 0xc4, 0x96, 0x18, 0x7d, 0xe3, 0x21, 0x6c, 0xf8, 0xa2, 0x69,
0xb4, 0xdf, 0x73, 0xbb, 0x3e, 0xc1, 0x1f, 0x43, 0xcc, 0xe9, 0x36, 0x5d, 0x6e, 0x39, 0x59, 0x7a, 0xd7, 0xed, 0x50, 0x82, 0x3f, 0x86, 0xb8, 0xd3, 0x69, 0xb8, 0x42, 0x72, 0xb2, 0xf8, 0xee, 0x2c,
0x77, 0x9e, 0x68, 0x77, 0x63, 0xec, 0x7d, 0x8b, 0xe3, 0x8c, 0x97, 0x08, 0xae, 0x3d, 0xe1, 0xec, 0xde, 0xee, 0xc6, 0xb9, 0x7e, 0x4b, 0xe0, 0x8c, 0xe7, 0x08, 0xae, 0x3c, 0x16, 0xd1, 0x0b, 0xac,
0x05, 0xde, 0x5e, 0xd1, 0x22, 0xbe, 0x0b, 0x49, 0x91, 0x0e, 0x5e, 0xc7, 0x9c, 0x9c, 0x8b, 0xf2, 0xbd, 0xa4, 0x44, 0x7c, 0x07, 0x92, 0x7e, 0x3a, 0x44, 0x1d, 0x8b, 0xe0, 0x4c, 0xcb, 0xe3, 0x3d,
0x78, 0x9f, 0x95, 0xfa, 0x81, 0xed, 0x1f, 0x5a, 0x32, 0xeb, 0x4c, 0x36, 0x3e, 0x87, 0xeb, 0x81, 0x5e, 0xea, 0x07, 0x36, 0x3d, 0xb2, 0x64, 0xd6, 0x39, 0x6d, 0x7c, 0x01, 0x57, 0x03, 0x6b, 0x96,
0x37, 0x2b, 0x0a, 0xd0, 0x04, 0xfc, 0xd0, 0xf1, 0x69, 0x45, 0xa8, 0x04, 0x41, 0x66, 0x61, 0xad, 0xe4, 0xa0, 0x09, 0xf8, 0x81, 0x43, 0x59, 0xd9, 0x67, 0x09, 0x9c, 0xcc, 0xc0, 0x6a, 0xc3, 0x69,
0xe9, 0xb4, 0x29, 0xf1, 0xfc, 0x2c, 0xd2, 0x95, 0x42, 0xc2, 0x0a, 0x8e, 0xc6, 0x13, 0x48, 0x8f, 0x31, 0xe2, 0xd1, 0x0c, 0xd2, 0x95, 0xfc, 0xba, 0x15, 0x1c, 0x8d, 0xc7, 0xb0, 0x39, 0xc2, 0x3f,
0xe9, 0x4f, 0xb9, 0xa1, 0x2c, 0xe5, 0x46, 0x0d, 0x32, 0xf7, 0x48, 0x9b, 0x50, 0x32, 0xe1, 0xc8, 0x61, 0x86, 0xb2, 0x90, 0x19, 0x55, 0x48, 0xdf, 0x25, 0x2d, 0xc2, 0xc8, 0x98, 0x21, 0xcb, 0xac,
0x2a, 0x6b, 0xe3, 0x25, 0x02, 0x6c, 0x11, 0xbb, 0xf1, 0xff, 0x3d, 0x81, 0x6f, 0x80, 0xea, 0x36, 0x8d, 0xe7, 0x08, 0xb0, 0x45, 0xec, 0xfa, 0xeb, 0x53, 0x81, 0xaf, 0x81, 0xea, 0x36, 0x1a, 0x94,
0x9b, 0x3e, 0xa1, 0xb2, 0xfd, 0xe5, 0x69, 0x38, 0x14, 0x94, 0xd1, 0x50, 0x30, 0xca, 0x90, 0x1e, 0x30, 0xd9, 0xfe, 0xf2, 0x34, 0x18, 0x0a, 0xca, 0x70, 0x28, 0x18, 0x25, 0xd8, 0x1c, 0xb1, 0x46,
0xf3, 0x46, 0x32, 0x39, 0x32, 0x81, 0x26, 0x4d, 0x34, 0x6c, 0x6a, 0x73, 0xc3, 0x1b, 0x16, 0x97, 0x46, 0x72, 0x28, 0x02, 0x8d, 0x8b, 0xa8, 0xdb, 0xcc, 0x16, 0x82, 0x37, 0x2c, 0x41, 0x1b, 0xbf,
0x8d, 0x9f, 0xa2, 0xa0, 0x3e, 0xa6, 0x36, 0xed, 0xfb, 0x6c, 0x3a, 0xf8, 0xd4, 0xf6, 0xe4, 0x74, 0xc4, 0x40, 0x7d, 0xc4, 0x6c, 0xd6, 0xa3, 0x7c, 0x3a, 0x50, 0x66, 0x7b, 0x72, 0x3a, 0xa0, 0x79,
0x40, 0x8b, 0x4c, 0x07, 0x89, 0x9b, 0x1a, 0x31, 0xd1, 0xe5, 0x46, 0x4c, 0x0a, 0x14, 0x8f, 0x34, 0xa6, 0x83, 0xc4, 0x4d, 0x8c, 0x98, 0xd8, 0x62, 0x23, 0x26, 0x05, 0x8a, 0x47, 0x1a, 0xc2, 0xd5,
0x79, 0xa8, 0x09, 0x8b, 0x89, 0xa1, 0x90, 0x62, 0x63, 0x21, 0x65, 0x20, 0x4e, 0x5d, 0x6a, 0xb7, 0x75, 0x8b, 0x93, 0x21, 0x97, 0xe2, 0x23, 0x2e, 0xa5, 0x21, 0xc1, 0x5c, 0x66, 0xb7, 0x32, 0x09,
0xb3, 0x71, 0x7e, 0x2d, 0x0e, 0xf8, 0x11, 0xac, 0x93, 0x6f, 0x7a, 0xa4, 0x4e, 0x49, 0x23, 0xab, 0x71, 0xed, 0x1f, 0xf0, 0x43, 0x58, 0x23, 0xdf, 0x76, 0x49, 0x8d, 0x91, 0x7a, 0x46, 0x5d, 0x38,
0x2e, 0x9d, 0x91, 0xa1, 0x0d, 0xe3, 0x26, 0x5c, 0x13, 0x1c, 0x05, 0x09, 0x97, 0x0e, 0xa2, 0xa1, 0x23, 0x03, 0x19, 0xc6, 0x75, 0xb8, 0xe2, 0xc7, 0x28, 0x48, 0xb8, 0x34, 0x10, 0x0d, 0x0c, 0xe4,
0x83, 0xac, 0xad, 0x02, 0x95, 0x61, 0x3d, 0xab, 0x3e, 0xbf, 0x91, 0x54, 0xbe, 0x37, 0xab, 0xa2, 0x6d, 0x15, 0xb0, 0x0c, 0xea, 0x59, 0xa5, 0xe2, 0x46, 0x86, 0xf2, 0xbd, 0xa8, 0x8a, 0x96, 0x78,
0x25, 0x5e, 0xa2, 0x8c, 0xa2, 0x68, 0x13, 0x71, 0x4b, 0xfc, 0xd9, 0x7d, 0xf5, 0x15, 0x64, 0xc6, 0x89, 0x32, 0x0a, 0x7e, 0x9b, 0xf8, 0xb7, 0x84, 0x46, 0xf7, 0xd5, 0xd7, 0x90, 0x1e, 0x05, 0x48,
0x01, 0xd2, 0x91, 0x07, 0xb0, 0xee, 0xcb, 0x3b, 0xd9, 0x5c, 0x73, 0xba, 0x22, 0xdb, 0x6b, 0x88, 0x43, 0xee, 0xc3, 0x1a, 0x95, 0x77, 0xb2, 0xb9, 0x66, 0x34, 0x45, 0xb6, 0xd7, 0x00, 0x6d, 0xfc,
0x36, 0xfe, 0x41, 0x90, 0x7e, 0xea, 0x39, 0x53, 0x2d, 0x56, 0x01, 0xd5, 0xae, 0x53, 0xc7, 0xed, 0xac, 0xc0, 0xe6, 0xa1, 0xe7, 0x4c, 0xb4, 0x58, 0x19, 0x54, 0xbb, 0xc6, 0x1c, 0xb7, 0x23, 0x5c,
0xf2, 0x50, 0xaf, 0x97, 0x6e, 0xcf, 0xb2, 0xcf, 0x8d, 0x94, 0x39, 0xc4, 0x92, 0xd0, 0x80, 0xd3, 0xbd, 0x5a, 0xbc, 0x19, 0x25, 0x5f, 0x08, 0x29, 0x09, 0x88, 0x25, 0xa1, 0x41, 0x4c, 0x63, 0xc3,
0xe8, 0x28, 0xe9, 0xc3, 0xe4, 0x2a, 0x97, 0x25, 0x37, 0x76, 0xf5, 0xe4, 0x86, 0x4a, 0x2b, 0x7e, 0xa4, 0x0f, 0x92, 0xab, 0x5c, 0x94, 0xdc, 0xf8, 0xe5, 0x93, 0x1b, 0x2a, 0xad, 0xc4, 0xd4, 0x6e,
0x61, 0xb7, 0xa8, 0xa1, 0x6e, 0x79, 0x1d, 0x85, 0xcc, 0x38, 0x01, 0x92, 0xe3, 0x95, 0x30, 0x30, 0x51, 0x87, 0xdd, 0x82, 0x0f, 0x07, 0xbb, 0x6f, 0x55, 0x04, 0xf2, 0x93, 0x99, 0x1c, 0x1d, 0x8d,
0xde, 0x80, 0xd1, 0x55, 0x34, 0xa0, 0xb2, 0x5c, 0x03, 0x2e, 0xd6, 0x6e, 0xa3, 0xf1, 0xa7, 0x5e, 0xd6, 0xb2, 0x57, 0xe1, 0xcb, 0x18, 0xa4, 0x47, 0xd5, 0xc8, 0xbc, 0x2f, 0x25, 0x2b, 0xa3, 0x43,
0x79, 0xc2, 0xea, 0xb0, 0x51, 0xae, 0xb9, 0x1e, 0xbd, 0xb4, 0xd3, 0x6e, 0x7d, 0x8f, 0x20, 0x19, 0x21, 0xb6, 0x8c, 0xa1, 0xa0, 0x2c, 0x36, 0x14, 0xe6, 0x1b, 0x01, 0xc3, 0x91, 0xac, 0x5e, 0x7a,
0x62, 0x0f, 0xbf, 0x03, 0xb1, 0xc7, 0xd5, 0x72, 0x35, 0x15, 0xd1, 0xd2, 0xc7, 0x27, 0xfa, 0x1b, 0xea, 0xeb, 0xb0, 0x51, 0xaa, 0xba, 0x1e, 0xbb, 0xb0, 0xfb, 0x6f, 0xfc, 0x80, 0x20, 0x19, 0x8a,
0xa1, 0x9f, 0x58, 0x15, 0xe3, 0x3c, 0xc4, 0x9f, 0x5a, 0xfb, 0xd5, 0xbd, 0x14, 0xd2, 0x32, 0xc7, 0x1e, 0x7e, 0x07, 0xe2, 0x8f, 0x2a, 0xa5, 0x4a, 0x6a, 0x45, 0xdb, 0x3c, 0x39, 0xd5, 0xdf, 0x08,
0x27, 0x7a, 0x2a, 0xf4, 0x3b, 0x17, 0xf1, 0x4d, 0x50, 0x2b, 0x9f, 0x1d, 0x1c, 0xec, 0x57, 0x53, 0x7d, 0xe2, 0x9d, 0x85, 0x73, 0x90, 0x38, 0xb4, 0xf6, 0x2b, 0x7b, 0x29, 0xa4, 0xa5, 0x4f, 0x4e,
0x51, 0xed, 0xad, 0xe3, 0x13, 0xfd, 0xcd, 0x90, 0x46, 0xc5, 0xed, 0x74, 0x1c, 0xaa, 0xa5, 0x7f, 0xf5, 0x54, 0xe8, 0xbb, 0x20, 0xf1, 0x75, 0x50, 0xcb, 0x9f, 0x1f, 0x1c, 0xec, 0x57, 0x52, 0x31,
0xf8, 0x39, 0x17, 0xf9, 0xf5, 0x97, 0x5c, 0xf8, 0xdd, 0xd2, 0x6f, 0x6b, 0xb0, 0x26, 0xcb, 0x00, 0xed, 0xad, 0x93, 0x53, 0xfd, 0xcd, 0x10, 0x47, 0xd9, 0x6d, 0xb7, 0x1d, 0xa6, 0x6d, 0xfe, 0xf8,
0xdb, 0xf2, 0x2b, 0xf0, 0xf6, 0x3c, 0x5b, 0x4b, 0x86, 0xa6, 0xbd, 0x3f, 0x9f, 0xb2, 0xac, 0xb0, 0x6b, 0x76, 0xe5, 0xf7, 0xdf, 0xb2, 0x61, 0xbd, 0xc5, 0x3f, 0x56, 0x61, 0x55, 0x96, 0x01, 0xb6,
0x16, 0xa8, 0x62, 0x6f, 0xe3, 0xcd, 0x59, 0xb8, 0xb1, 0xaf, 0x0d, 0xcd, 0x9c, 0x57, 0x5d, 0x3e, 0xe5, 0xcb, 0xf4, 0xe6, 0x2c, 0x9b, 0x54, 0xba, 0xa6, 0xbd, 0x3f, 0x1b, 0xb3, 0xac, 0xb0, 0x26,
0xf4, 0x02, 0x62, 0x6c, 0x8c, 0xe0, 0xd2, 0x2c, 0xdc, 0xf4, 0xd2, 0xd7, 0xb6, 0x17, 0xc2, 0x88, 0xa8, 0xfe, 0x5b, 0x02, 0x6f, 0x45, 0xe1, 0x46, 0x5e, 0x40, 0x9a, 0x39, 0x2b, 0xbb, 0x54, 0xf4,
0x07, 0xb7, 0x10, 0xfe, 0x02, 0x54, 0xb1, 0xba, 0xf1, 0xce, 0x2c, 0x03, 0x17, 0xad, 0x78, 0xed, 0x0c, 0xe2, 0x7c, 0xb4, 0xe1, 0x62, 0x14, 0x6e, 0xf2, 0x21, 0xa2, 0xed, 0xcc, 0x85, 0xf1, 0x15,
0xc6, 0x54, 0x7d, 0xef, 0xb1, 0x6f, 0x74, 0x16, 0x0a, 0xdb, 0x8f, 0xb3, 0x43, 0x99, 0xde, 0xe9, 0x6e, 0x23, 0xfc, 0x25, 0xa8, 0xfe, 0x73, 0x02, 0xdf, 0x8e, 0x12, 0x30, 0xed, 0xd9, 0xa1, 0x5d,
0xb3, 0x43, 0xb9, 0x60, 0xf3, 0x6e, 0x21, 0x96, 0x26, 0xb9, 0x4e, 0x37, 0xe7, 0x9c, 0xf7, 0xf3, 0x9b, 0xa8, 0xef, 0x3d, 0xfe, 0xbf, 0x81, 0xbb, 0xc2, 0x77, 0x76, 0xb4, 0x2b, 0x93, 0xef, 0x8c,
0xa6, 0x69, 0x62, 0xbd, 0x1c, 0xc1, 0x46, 0x78, 0xda, 0xe3, 0xb9, 0xa8, 0x9f, 0x58, 0x26, 0xda, 0x68, 0x57, 0xa6, 0xbc, 0x06, 0xb6, 0x11, 0x4f, 0x93, 0x5c, 0xf1, 0x5b, 0x33, 0xee, 0xa0, 0x59,
0xce, 0x62, 0x20, 0xf9, 0xf4, 0x00, 0xe2, 0xa2, 0x75, 0xb6, 0xe7, 0x9a, 0x72, 0x13, 0xc4, 0xee, 0xd3, 0x34, 0xb6, 0xf2, 0x8e, 0x61, 0x23, 0xbc, 0x81, 0xf0, 0x4c, 0xa1, 0x1f, 0x5b, 0x70, 0xda,
0x2c, 0x06, 0x12, 0x6f, 0x16, 0xd0, 0x16, 0xc2, 0x07, 0x10, 0xe7, 0xb3, 0x01, 0xcf, 0xec, 0x9c, 0xed, 0xf9, 0x40, 0x52, 0x75, 0x1f, 0x12, 0x7e, 0xeb, 0xec, 0x2c, 0x30, 0x92, 0xa3, 0x75, 0x4e,
0xf0, 0x08, 0xb9, 0xac, 0x3a, 0x76, 0x9f, 0x9d, 0x9e, 0xe5, 0x22, 0x7f, 0x9c, 0xe5, 0x22, 0xdf, 0x1b, 0xb0, 0x79, 0xb4, 0x8d, 0xf0, 0x01, 0x24, 0xc4, 0x6c, 0xc0, 0x91, 0x9d, 0x13, 0x1e, 0x21,
0x9d, 0xe7, 0xd0, 0xe9, 0x79, 0x0e, 0xfd, 0x7e, 0x9e, 0x43, 0x7f, 0x9d, 0xe7, 0xd0, 0xb3, 0x4f, 0x17, 0x55, 0xc7, 0xee, 0x93, 0xb3, 0x57, 0xd9, 0x95, 0xbf, 0x5e, 0x65, 0x57, 0xbe, 0x3f, 0xcf,
0x96, 0xfd, 0x9f, 0xf5, 0xae, 0x14, 0x6b, 0x2a, 0x7f, 0x6b, 0xfb, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xa2, 0xb3, 0xf3, 0x2c, 0xfa, 0xf3, 0x3c, 0x8b, 0xfe, 0x39, 0xcf, 0xa2, 0x27, 0x9f, 0x2e, 0xfa,
0xff, 0x28, 0x28, 0x53, 0x76, 0xfe, 0x0e, 0x00, 0x00, 0x3f, 0xfa, 0x8e, 0x24, 0xab, 0xaa, 0xd0, 0xb5, 0xf3, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf,
0xc1, 0xae, 0xf1, 0x92, 0x0f, 0x00, 0x00,
} }

View File

@ -269,6 +269,9 @@ message WriteContentRequest {
// If this is empty and the message is not a commit, a response will be // If this is empty and the message is not a commit, a response will be
// returned with the current write state. // returned with the current write state.
bytes data = 6; bytes data = 6;
// Labels are arbitrary data to set on commit.
map<string, string> labels = 7;
} }
// WriteContentResponse is returned on the culmination of a write call. // WriteContentResponse is returned on the culmination of a write call.

View File

@ -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.
@ -68,15 +74,16 @@ func (x Status) String() string {
func (Status) EnumDescriptor() ([]byte, []int) { return fileDescriptorTask, []int{0} } func (Status) EnumDescriptor() ([]byte, []int) { return fileDescriptorTask, []int{0} }
type Process struct { type Process struct {
ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"`
Status Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` Status Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"`
Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"`
Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"`
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,
} }

View File

@ -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];
} }

View File

@ -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,
} }
} }

View File

@ -174,6 +174,10 @@ func (c *container) NewTask(ctx context.Context, ioCreate IOCreation, opts ...Ne
Stderr: cfg.Stderr, Stderr: cfg.Stderr,
} }
if c.c.RootFS != "" { if c.c.RootFS != "" {
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.RootFS)
if err != nil { if err != nil {

View File

@ -4,7 +4,9 @@ import (
"context" "context"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"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
@ -38,6 +40,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,6 +52,7 @@ 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
@ -65,6 +70,7 @@ func WithNewSnapshot(id string, i Image) NewContainerOpts {
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
} }
@ -77,6 +83,9 @@ func WithNewSnapshot(id string, i Image) NewContainerOpts {
// WithSnapshotCleanup deletes the rootfs allocated for the container // WithSnapshotCleanup deletes the rootfs 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.RootFS != "" {
if c.Snapshotter == "" {
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs")
}
return client.SnapshotService(c.Snapshotter).Remove(ctx, c.RootFS) return client.SnapshotService(c.Snapshotter).Remove(ctx, c.RootFS)
} }
return nil return nil
@ -90,6 +99,7 @@ func WithNewSnapshotView(id string, i Image) NewContainerOpts {
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
} }
@ -98,3 +108,9 @@ func WithNewSnapshotView(id string, i Image) NewContainerOpts {
return nil return nil
} }
} }
func setSnapshotterIfEmpty(c *containers.Container) {
if c.Snapshotter == "" {
c.Snapshotter = DefaultSnapshotter
}
}

View File

@ -46,6 +46,7 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
if err != nil { if err != nil {
return err return err
} }
setSnapshotterIfEmpty(c)
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, rootfsID, identity.ChainID(diffIDs).String()); err != nil { if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, rootfsID, identity.ChainID(diffIDs).String()); err != nil {
if !errdefs.IsAlreadyExists(err) { if !errdefs.IsAlreadyExists(err) {
return err return err

View File

@ -12,15 +12,51 @@ 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 string // ID uniquely identifies the container in a nameapace.
Labels map[string]string //
Image string // This property is required and cannot be changed after creation.
Runtime RuntimeInfo ID string
Spec *types.Any
RootFS string // Labels provide metadata extension for a contaienr.
//
// These are optional and fully mutable.
Labels map[string]string
// Image specifies the image reference used for a container.
//
// This property is optional but immutable.
Image string
// Runtime specifies which runtime should be used when launching container
// tasks.
//
// This property is required and immutable.
Runtime RuntimeInfo
// Spec should carry the the runtime specification used to implement the
// container.
//
// This field is required but mutable.
Spec *types.Any
// RootFS 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.
RootFS string
// Snapshotter specifies the snapshotter name used for rootfs
//
// This field is not required but immutable.
Snapshotter string Snapshotter string
CreatedAt time.Time
UpdatedAt time.Time // CreatedAt is the time at which the container was created.
CreatedAt time.Time
// UpdatedAt is the time at which the container was updated.
UpdatedAt time.Time
} }
type RuntimeInfo struct { type RuntimeInfo struct {
@ -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
} }

View File

@ -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) error Commit(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)
@ -107,3 +107,13 @@ type Store interface {
IngestManager IngestManager
Ingester Ingester
} }
// Opt is used to alter the mutable properties of content
type Opt func(*Info) error
func WithLabels(labels map[string]string) Opt {
return func(info *Info) error {
info.Labels = labels
return nil
}
}

View File

@ -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")
ErrNotSupported = errors.New("not supported") // 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 IsNotSupported(err error) bool {
return errors.Cause(err) == ErrNotSupported
}

View File

@ -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 IsNotSupported(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 = ErrNotSupported
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 = errors.WithStack(cls)
err = cls
}
} }
return err return err

View File

@ -67,6 +67,11 @@ 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
// 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) (ocispec.Descriptor, error) { func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor) (ocispec.Descriptor, error) {
var configDesc ocispec.Descriptor var configDesc ocispec.Descriptor
return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {

View File

@ -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

View File

@ -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)
}

View File

@ -38,17 +38,18 @@ var (
bucketKeyObjectBlob = []byte("blob") // stores content links bucketKeyObjectBlob = []byte("blob") // stores content links
bucketKeyObjectIngest = []byte("ingest") // stores ingest links bucketKeyObjectIngest = []byte("ingest") // stores ingest links
bucketKeyDigest = []byte("digest") bucketKeyDigest = []byte("digest")
bucketKeyMediaType = []byte("mediatype") bucketKeyMediaType = []byte("mediatype")
bucketKeySize = []byte("size") bucketKeySize = []byte("size")
bucketKeyImage = []byte("image") bucketKeyImage = []byte("image")
bucketKeyRuntime = []byte("runtime") bucketKeyRuntime = []byte("runtime")
bucketKeyName = []byte("name") bucketKeyName = []byte("name")
bucketKeyParent = []byte("parent") bucketKeyParent = []byte("parent")
bucketKeyOptions = []byte("options") bucketKeyOptions = []byte("options")
bucketKeySpec = []byte("spec") bucketKeySpec = []byte("spec")
bucketKeyRootFS = []byte("rootfs") bucketKeyRootFS = []byte("rootfs")
bucketKeyTarget = []byte("target") bucketKeySnapshotter = []byte("snapshotter")
bucketKeyTarget = []byte("target")
) )
func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket { func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {

View File

@ -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,37 +144,55 @@ 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.RootFS != container.RootFS {
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.RootFS 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 { for _, path := range fieldpaths {
// TODO(stevvooe): Move this logic into the store itself. if strings.HasPrefix(path, "labels.") {
for _, path := range fieldpaths { if updated.Labels == nil {
if strings.HasPrefix(path, "labels.") { updated.Labels = map[string]string{}
if updated.Labels == nil {
updated.Labels = map[string]string{}
}
key := strings.TrimPrefix(path, "labels.")
updated.Labels[key] = container.Labels[key]
continue
}
switch path {
case "labels":
updated.Labels = container.Labels
case "image":
updated.Image = container.Image
case "spec":
updated.Spec = container.Spec
case "rootfs":
updated.RootFS = container.RootFS
default:
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
} }
key := strings.TrimPrefix(path, "labels.")
updated.Labels[key] = container.Labels[key]
continue
} }
} else {
// no field mask present, just replace everything switch path {
updated = container case "labels":
updated.Labels = container.Labels
case "spec":
updated.Spec = container.Spec
default:
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
}
}
if err := validateContainer(&updated); err != nil {
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.RootFS != "" && container.Snapshotter == "" {
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set if container.RootFS 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 {
@ -247,7 +286,8 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error {
container.Spec = &any container.Spec = &any
case string(bucketKeyRootFS): case string(bucketKeyRootFS):
container.RootFS = string(v) container.RootFS = string(v)
case string(bucketKeySnapshotter):
container.Snapshotter = string(v)
} }
return nil return nil
@ -272,6 +312,7 @@ 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)},
{bucketKeySnapshotter, []byte(container.Snapshotter)},
{bucketKeyRootFS, []byte(container.RootFS)}, {bucketKeyRootFS, []byte(container.RootFS)},
} { } {
if err := bkt.Put(v[0], v[1]); err != nil { if err := bkt.Put(v[0], v[1]); err != nil {

View File

@ -170,7 +170,7 @@ func (cs *contentStore) Delete(ctx context.Context, dgst digest.Digest) error {
// Just remove local reference, garbage collector is responsible for // Just remove local reference, garbage collector is responsible for
// cleaning up on disk content // cleaning up on disk content
return getBlobsBucket(tx, ns).Delete([]byte(dgst.String())) return getBlobsBucket(tx, ns).DeleteBucket([]byte(dgst.String()))
}) })
} }
@ -352,7 +352,7 @@ type namespacedWriter struct {
db *bolt.DB db *bolt.DB
} }
func (nw *namespacedWriter) Commit(size int64, expected digest.Digest) error { func (nw *namespacedWriter) Commit(size int64, expected digest.Digest, opts ...content.Opt) error {
return nw.db.Update(func(tx *bolt.Tx) error { return nw.db.Update(func(tx *bolt.Tx) error {
bkt := getIngestBucket(tx, nw.namespace) bkt := getIngestBucket(tx, nw.namespace)
if bkt != nil { if bkt != nil {
@ -360,11 +360,17 @@ func (nw *namespacedWriter) Commit(size int64, expected digest.Digest) error {
return err return err
} }
} }
return nw.commit(tx, size, expected) return nw.commit(tx, size, expected, opts...)
}) })
} }
func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Digest) error { func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Digest, opts ...content.Opt) error {
var base content.Info
for _, opt := range opts {
if err := opt(&base); err != nil {
return err
}
}
status, err := nw.Writer.Status() status, err := nw.Writer.Status()
if err != nil { if err != nil {
return err return err
@ -400,6 +406,9 @@ func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Dige
if err := boltutil.WriteTimestamps(bkt, commitTime, commitTime); err != nil { if err := boltutil.WriteTimestamps(bkt, commitTime, commitTime); err != nil {
return err return err
} }
if err := boltutil.WriteLabels(bkt, base.Labels); err != nil {
return err
}
if err := bkt.Put(bucketKeySize, sizeEncoded); err != nil { if err := bkt.Put(bucketKeySize, sizeEncoded); err != nil {
return err return err
} }

View File

@ -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
} }

View File

@ -4,6 +4,7 @@ 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"
@ -21,11 +22,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) 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,6 +37,41 @@ 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
@ -79,39 +115,55 @@ func (p *process) Kill(ctx context.Context, s syscall.Signal) error {
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
} }
for {
evt, err := eventstream.Recv() go func() {
if err != nil { defer cancel()
return UnknownExitStatus, err chStatus <- ExitStatus{} // signal that the goroutine is running
} for {
if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) { evt, err := eventstream.Recv()
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) if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) {
if e.ID == p.id && e.ContainerID == p.task.id { v, err := typeurl.UnmarshalAny(evt.Event)
return e.ExitStatus, nil if err != nil {
chStatus <- ExitStatus{code: UnknownExitStatus, err: err}
return
}
e := v.(*eventsapi.TaskExit)
if e.ID == p.id && e.ContainerID == p.task.id {
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 +194,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) {

View File

@ -215,7 +215,7 @@ func (pw *pushWriter) Digest() digest.Digest {
return pw.expected return pw.expected
} }
func (pw *pushWriter) Commit(size int64, expected digest.Digest) error { func (pw *pushWriter) Commit(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")

View File

@ -49,5 +49,5 @@ func Diff(ctx context.Context, snapshotID, contentRef string, sn snapshot.Snapsh
defer sn.Remove(ctx, lowerKey) defer sn.Remove(ctx, lowerKey)
} }
return md.DiffMounts(ctx, lower, upper, ocispec.MediaTypeImageLayer, contentRef) return md.DiffMounts(ctx, lower, upper, ocispec.MediaTypeImageLayerGzip, contentRef)
} }

View File

@ -2,6 +2,7 @@ package runtime
import ( import (
"context" "context"
"time"
"github.com/gogo/protobuf/types" "github.com/gogo/protobuf/types"
) )
@ -77,10 +78,13 @@ 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
Stdin string // ExitedAt is the time at which the process exited
Stdout string // Only valid if the Status is Stopped
Stderr string ExitedAt time.Time
Terminal bool Stdin string
Stdout string
Stderr string
Terminal bool
} }

View File

@ -420,7 +420,11 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
} }
if req.Action == api.WriteActionCommit { if req.Action == api.WriteActionCommit {
if err := wr.Commit(total, expected); err != nil { var opts []content.Opt
if req.Labels != nil {
opts = append(opts, content.WithLabels(req.Labels))
}
if err := wr.Commit(total, expected, opts...); err != nil {
return err return err
} }
} }

View File

@ -46,6 +46,7 @@ func (rw *remoteWriter) Status() (content.Status, error) {
return content.Status{ return content.Status{
Ref: rw.ref, Ref: rw.ref,
Offset: resp.Offset, Offset: resp.Offset,
Total: resp.Total,
StartedAt: resp.StartedAt, StartedAt: resp.StartedAt,
UpdatedAt: resp.UpdatedAt, UpdatedAt: resp.UpdatedAt,
}, nil }, nil
@ -79,12 +80,19 @@ func (rw *remoteWriter) Write(p []byte) (n int, err error) {
return return
} }
func (rw *remoteWriter) Commit(size int64, expected digest.Digest) error { func (rw *remoteWriter) Commit(size int64, expected digest.Digest, opts ...content.Opt) error {
var base content.Info
for _, opt := range opts {
if err := opt(&base); err != nil {
return err
}
}
resp, err := rw.send(&contentapi.WriteContentRequest{ resp, err := rw.send(&contentapi.WriteContentRequest{
Action: contentapi.WriteActionCommit, Action: contentapi.WriteActionCommit,
Total: size, Total: size,
Offset: rw.offset, Offset: rw.offset,
Expected: expected, Expected: expected,
Labels: base.Labels,
}) })
if err != nil { if err != nil {
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)

View File

@ -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.IsNotSupported(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.IsNotSupported(err) {
break
}
}
if err != nil { if err != nil {
return nil, errdefs.ToGRPC(err) return nil, errdefs.ToGRPC(err)
} }

View File

@ -1,5 +0,0 @@
package snapshot
const (
defaultSnapshotter = "overlayfs"
)

View File

@ -1,7 +0,0 @@
// +build darwin freebsd solaris
package snapshot
const (
defaultSnapshotter = "naive"
)

View File

@ -1,5 +0,0 @@
package snapshot
const (
defaultSnapshotter = "windows"
)

View File

@ -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,
}) })
} }
@ -43,9 +35,8 @@ func init() {
var empty = &protoempty.Empty{} 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
} }
func newService(ic *plugin.InitContext) (interface{}, error) { func newService(ic *plugin.InitContext) (interface{}, error) {
@ -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
} }

View 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"
)

View 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"
)

View 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"
)

View File

@ -176,8 +176,8 @@ func WithHostHostsFile(s *specs.Spec) error {
return nil return nil
} }
// WithHostResoveconf 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 WithHostResoveconf(s *specs.Spec) error { func WithHostResolvconf(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",
@ -233,6 +233,9 @@ func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts
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()

View File

@ -171,9 +171,6 @@ func incrementFS(root string, uidInc, gidInc uint32) filepath.WalkFunc {
if err != nil { if err != nil {
return err return err
} }
if root == path {
return nil
}
var ( var (
stat = info.Sys().(*syscall.Stat_t) stat = info.Sys().(*syscall.Stat_t)
u, g = int(stat.Uid + uidInc), int(stat.Gid + gidInc) u, g = int(stat.Uid + uidInc), int(stat.Gid + gidInc)

View File

@ -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"
@ -17,6 +18,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/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/rootfs" "github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/typeurl" "github.com/containerd/containerd/typeurl"
@ -37,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
@ -117,7 +121,8 @@ type Task interface {
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
@ -192,18 +197,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()
@ -211,47 +220,67 @@ 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
} }
} }
for {
evt, err := eventstream.Recv() go func() {
if err != nil { defer cancel()
return UnknownExitStatus, errdefs.FromGRPC(err) chStatus <- ExitStatus{} // signal that goroutine is running
} for {
if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) { evt, err := eventstream.Recv()
v, err := typeurl.UnmarshalAny(evt.Event)
if err != nil { if err != nil {
return UnknownExitStatus, err chStatus <- ExitStatus{code: UnknownExitStatus, err: errdefs.FromGRPC(err)}
return
} }
e := v.(*eventsapi.TaskExit) if typeurl.Is(evt.Event, &eventsapi.TaskExit{}) {
if e.ContainerID == t.id && e.Pid == t.pid { v, err := typeurl.UnmarshalAny(evt.Event)
return e.ExitStatus, nil if err != nil {
chStatus <- ExitStatus{code: UnknownExitStatus, err: err}
return
}
e := v.(*eventsapi.TaskExit)
if e.ContainerID == t.id && e.Pid == t.pid {
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, "":
case Created:
if t.client.runtime == fmt.Sprintf("%s.%s", plugin.RuntimePlugin, "windows") {
// On windows Created is akin to Stopped
break
}
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()
@ -262,9 +291,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) {

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"syscall" "syscall"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/linux/runcopts" "github.com/containerd/containerd/linux/runcopts"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
) )
@ -32,14 +33,20 @@ 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)
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
}() }
p.Kill(ctx, syscall.SIGKILL) if err := p.Kill(ctx, syscall.SIGKILL); err != nil {
if errdefs.IsFailedPrecondition(err) || errdefs.IsNotFound(err) {
return nil
}
return err
}
// wait for the process to fully stop before letting the rest of the deletion complete // wait for the process to fully stop before letting the rest of the deletion complete
<-s <-s
return nil return nil

View File

@ -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 b85ac701de5065a66918203dd18f057433290807
github.com/containerd/console 76d18fd1d66972718ab2284449591db0b3cdb4de github.com/containerd/console 76d18fd1d66972718ab2284449591db0b3cdb4de
github.com/containerd/cgroups 4fd64a776f25b5540cddcb72eea6e35e58baca6e github.com/containerd/cgroups e6d1aa8c71c6103624b2c6e6f4be0863b67027f1
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
@ -17,7 +17,7 @@ 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 e775f0fba3ea329b8b766451c892c41a3d49594d
github.com/sirupsen/logrus v1.0.0 github.com/sirupsen/logrus v1.0.0
github.com/containerd/btrfs e9c546f46bccffefe71a6bc137e4c21b5503cc18 github.com/containerd/btrfs cc52c4dea2ce11a44e6639e561bb5c2af9ada9e3
github.com/stretchr/testify v1.1.4 github.com/stretchr/testify v1.1.4
github.com/davecgh/go-spew v1.1.0 github.com/davecgh/go-spew v1.1.0
github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib v1.0.0