Refactor shim terminal and io handling

This also finishes the service implementation of the shim behind GRPC

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2017-01-23 16:18:10 -08:00
parent 6e9e0a895a
commit d5d2e586cd
12 changed files with 547 additions and 630 deletions

View file

@ -51,9 +51,14 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
type CreateRequest struct {
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"`
Runtime string `protobuf:"bytes,3,opt,name=runtime,proto3" json:"runtime,omitempty"`
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"`
Runtime string `protobuf:"bytes,3,opt,name=runtime,proto3" json:"runtime,omitempty"`
NoPivot bool `protobuf:"varint,4,opt,name=no_pivot,json=noPivot,proto3" json:"no_pivot,omitempty"`
Terminal bool `protobuf:"varint,5,opt,name=terminal,proto3" json:"terminal,omitempty"`
Stdin string `protobuf:"bytes,6,opt,name=stdin,proto3" json:"stdin,omitempty"`
Stdout string `protobuf:"bytes,7,opt,name=stdout,proto3" json:"stdout,omitempty"`
Stderr string `protobuf:"bytes,8,opt,name=stderr,proto3" json:"stderr,omitempty"`
}
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
@ -76,6 +81,7 @@ func (*StartRequest) ProtoMessage() {}
func (*StartRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{2} }
type DeleteRequest struct {
Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"`
}
func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
@ -106,7 +112,7 @@ func (*ExecResponse) ProtoMessage() {}
func (*ExecResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{6} }
type PtyRequest struct {
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"`
Width uint32 `protobuf:"varint,2,opt,name=width,proto3" json:"width,omitempty"`
Height uint32 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
}
@ -129,11 +135,16 @@ func (this *CreateRequest) GoString() string {
if this == nil {
return "nil"
}
s := make([]string, 0, 7)
s := make([]string, 0, 12)
s = append(s, "&shim.CreateRequest{")
s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
s = append(s, "Bundle: "+fmt.Sprintf("%#v", this.Bundle)+",\n")
s = append(s, "Runtime: "+fmt.Sprintf("%#v", this.Runtime)+",\n")
s = append(s, "NoPivot: "+fmt.Sprintf("%#v", this.NoPivot)+",\n")
s = append(s, "Terminal: "+fmt.Sprintf("%#v", this.Terminal)+",\n")
s = append(s, "Stdin: "+fmt.Sprintf("%#v", this.Stdin)+",\n")
s = append(s, "Stdout: "+fmt.Sprintf("%#v", this.Stdout)+",\n")
s = append(s, "Stderr: "+fmt.Sprintf("%#v", this.Stderr)+",\n")
s = append(s, "}")
return strings.Join(s, "")
}
@ -160,8 +171,9 @@ func (this *DeleteRequest) GoString() string {
if this == nil {
return "nil"
}
s := make([]string, 0, 4)
s := make([]string, 0, 5)
s = append(s, "&shim.DeleteRequest{")
s = append(s, "Pid: "+fmt.Sprintf("%#v", this.Pid)+",\n")
s = append(s, "}")
return strings.Join(s, "")
}
@ -200,7 +212,7 @@ func (this *PtyRequest) GoString() string {
}
s := make([]string, 0, 7)
s = append(s, "&shim.PtyRequest{")
s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
s = append(s, "Pid: "+fmt.Sprintf("%#v", this.Pid)+",\n")
s = append(s, "Width: "+fmt.Sprintf("%#v", this.Width)+",\n")
s = append(s, "Height: "+fmt.Sprintf("%#v", this.Height)+",\n")
s = append(s, "}")
@ -470,6 +482,44 @@ func (m *CreateRequest) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintShim(dAtA, i, uint64(len(m.Runtime)))
i += copy(dAtA[i:], m.Runtime)
}
if m.NoPivot {
dAtA[i] = 0x20
i++
if m.NoPivot {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
if m.Terminal {
dAtA[i] = 0x28
i++
if m.Terminal {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
if len(m.Stdin) > 0 {
dAtA[i] = 0x32
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin)))
i += copy(dAtA[i:], m.Stdin)
}
if len(m.Stdout) > 0 {
dAtA[i] = 0x3a
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout)))
i += copy(dAtA[i:], m.Stdout)
}
if len(m.Stderr) > 0 {
dAtA[i] = 0x42
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr)))
i += copy(dAtA[i:], m.Stderr)
}
return i, nil
}
@ -529,6 +579,11 @@ func (m *DeleteRequest) MarshalTo(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.Pid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintShim(dAtA, i, uint64(m.Pid))
}
return i, nil
}
@ -611,11 +666,10 @@ func (m *PtyRequest) MarshalTo(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.ID) > 0 {
dAtA[i] = 0xa
if m.Pid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.ID)))
i += copy(dAtA[i:], m.ID)
i = encodeVarintShim(dAtA, i, uint64(m.Pid))
}
if m.Width != 0 {
dAtA[i] = 0x10
@ -672,6 +726,24 @@ func (m *CreateRequest) Size() (n int) {
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
if m.NoPivot {
n += 2
}
if m.Terminal {
n += 2
}
l = len(m.Stdin)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
l = len(m.Stdout)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
l = len(m.Stderr)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
return n
}
@ -693,6 +765,9 @@ func (m *StartRequest) Size() (n int) {
func (m *DeleteRequest) Size() (n int) {
var l int
_ = l
if m.Pid != 0 {
n += 1 + sovShim(uint64(m.Pid))
}
return n
}
@ -723,9 +798,8 @@ func (m *ExecResponse) Size() (n int) {
func (m *PtyRequest) Size() (n int) {
var l int
_ = l
l = len(m.ID)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
if m.Pid != 0 {
n += 1 + sovShim(uint64(m.Pid))
}
if m.Width != 0 {
n += 1 + sovShim(uint64(m.Width))
@ -757,6 +831,11 @@ func (this *CreateRequest) String() string {
`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
`Bundle:` + fmt.Sprintf("%v", this.Bundle) + `,`,
`Runtime:` + fmt.Sprintf("%v", this.Runtime) + `,`,
`NoPivot:` + fmt.Sprintf("%v", this.NoPivot) + `,`,
`Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`,
`Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`,
`Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`,
`Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`,
`}`,
}, "")
return s
@ -785,6 +864,7 @@ func (this *DeleteRequest) String() string {
return "nil"
}
s := strings.Join([]string{`&DeleteRequest{`,
`Pid:` + fmt.Sprintf("%v", this.Pid) + `,`,
`}`,
}, "")
return s
@ -823,7 +903,7 @@ func (this *PtyRequest) String() string {
return "nil"
}
s := strings.Join([]string{`&PtyRequest{`,
`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
`Pid:` + fmt.Sprintf("%v", this.Pid) + `,`,
`Width:` + fmt.Sprintf("%v", this.Width) + `,`,
`Height:` + fmt.Sprintf("%v", this.Height) + `,`,
`}`,
@ -954,6 +1034,133 @@ func (m *CreateRequest) Unmarshal(dAtA []byte) error {
}
m.Runtime = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field NoPivot", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.NoPivot = bool(v != 0)
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Terminal", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Terminal = bool(v != 0)
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stdin", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
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 ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stdin = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stdout", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
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 ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stdout = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Stderr", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
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 ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Stderr = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipShim(dAtA[iNdEx:])
@ -1123,6 +1330,25 @@ func (m *DeleteRequest) Unmarshal(dAtA []byte) error {
return fmt.Errorf("proto: DeleteRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Pid", wireType)
}
m.Pid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Pid |= (uint32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipShim(dAtA[iNdEx:])
@ -1362,10 +1588,10 @@ func (m *PtyRequest) Unmarshal(dAtA []byte) error {
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Pid", wireType)
}
var stringLen uint64
m.Pid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
@ -1375,21 +1601,11 @@ func (m *PtyRequest) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
m.Pid |= (uint32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Width", wireType)
@ -1557,32 +1773,36 @@ var (
func init() { proto.RegisterFile("shim.proto", fileDescriptorShim) }
var fileDescriptorShim = []byte{
// 419 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x92, 0xbf, 0x8e, 0xd3, 0x40,
0x10, 0xc6, 0xcf, 0x0e, 0x67, 0xc4, 0xe4, 0x1c, 0xd0, 0xea, 0x14, 0x19, 0xe7, 0xf0, 0x9d, 0x5c,
0x51, 0x39, 0x3a, 0x68, 0x28, 0x90, 0x90, 0x42, 0x52, 0xd0, 0x45, 0x76, 0x45, 0x85, 0x9c, 0x78,
0xb0, 0x57, 0x8a, 0xbd, 0xc6, 0x5e, 0x87, 0xa4, 0xe3, 0xf1, 0x52, 0x52, 0x50, 0x50, 0x21, 0xe2,
0x27, 0xe0, 0x11, 0xd0, 0xae, 0xd7, 0x90, 0x38, 0x44, 0x74, 0x3b, 0x7f, 0xf4, 0xed, 0x37, 0xbf,
0x19, 0x80, 0x32, 0xa1, 0xa9, 0x97, 0x17, 0x8c, 0x33, 0x62, 0x2e, 0x59, 0xc6, 0x43, 0x9a, 0x61,
0x11, 0x79, 0xeb, 0x7b, 0x7b, 0x14, 0x33, 0x16, 0xaf, 0x70, 0x2c, 0x8b, 0x8b, 0xea, 0xe3, 0x18,
0xd3, 0x9c, 0x6f, 0x9b, 0x5e, 0xfb, 0x3a, 0x66, 0x31, 0x93, 0xcf, 0xb1, 0x78, 0x35, 0x59, 0xf7,
0x3d, 0x98, 0x6f, 0x0b, 0x0c, 0x39, 0xfa, 0xf8, 0xa9, 0xc2, 0x92, 0x93, 0x21, 0xe8, 0x34, 0xb2,
0xb4, 0x3b, 0xed, 0xf9, 0xa3, 0x89, 0x51, 0xff, 0xb8, 0xd5, 0xdf, 0x4d, 0x7d, 0x9d, 0x46, 0x64,
0x08, 0xc6, 0xa2, 0xca, 0xa2, 0x15, 0x5a, 0xba, 0xa8, 0xf9, 0x2a, 0x22, 0x16, 0x3c, 0x2c, 0xaa,
0x8c, 0xd3, 0x14, 0xad, 0x9e, 0x2c, 0xb4, 0xa1, 0xeb, 0xc2, 0xa0, 0x95, 0x2e, 0x73, 0x96, 0x95,
0x48, 0x9e, 0x40, 0x2f, 0x57, 0xe2, 0xa6, 0x2f, 0x9e, 0xee, 0x00, 0xae, 0x02, 0x1e, 0x16, 0x5c,
0xfd, 0xee, 0x3e, 0x06, 0x73, 0x8a, 0x2b, 0xfc, 0x63, 0xc7, 0xbd, 0x87, 0x41, 0x9b, 0x50, 0x22,
0xb7, 0xd0, 0xc7, 0x0d, 0xe5, 0x1f, 0x4a, 0x1e, 0xf2, 0xaa, 0x54, 0x62, 0x20, 0x52, 0x81, 0xcc,
0xb8, 0x26, 0xf4, 0x67, 0x1b, 0x5c, 0xb6, 0x0a, 0x77, 0x70, 0xd5, 0x84, 0x67, 0x4d, 0xf8, 0x00,
0x73, 0xbe, 0xfd, 0x1f, 0x80, 0x6b, 0xb8, 0xfc, 0x4c, 0x23, 0x9e, 0xc8, 0xf9, 0x4d, 0xbf, 0x09,
0x04, 0x96, 0x04, 0x69, 0x9c, 0x70, 0x39, 0xbd, 0xe9, 0xab, 0xe8, 0xc5, 0x37, 0x1d, 0xfa, 0x41,
0x42, 0xd3, 0x00, 0x8b, 0x35, 0x5d, 0x22, 0x99, 0x81, 0xd1, 0xc0, 0x20, 0x37, 0xde, 0xd1, 0xd2,
0xbc, 0x23, 0xfc, 0xf6, 0xb3, 0x33, 0x55, 0x65, 0xfe, 0x35, 0x5c, 0x4a, 0x5e, 0x64, 0xd4, 0xe9,
0x3b, 0xa4, 0x68, 0x0f, 0xbd, 0xe6, 0x10, 0xbc, 0xf6, 0x10, 0xbc, 0x99, 0x38, 0x04, 0x61, 0xa2,
0x81, 0x79, 0x62, 0xe2, 0x08, 0xfa, 0x89, 0x89, 0xce, 0x06, 0xde, 0xc0, 0x03, 0x41, 0x94, 0xd8,
0x9d, 0xb6, 0x03, 0xea, 0xf6, 0xe8, 0x9f, 0x35, 0x25, 0xf0, 0x0a, 0x7a, 0x73, 0xbe, 0x25, 0x4f,
0x3b, 0x3d, 0x7f, 0x97, 0x70, 0x6e, 0x82, 0xc9, 0xcd, 0x6e, 0xef, 0x5c, 0x7c, 0xdf, 0x3b, 0x17,
0xbf, 0xf6, 0x8e, 0xf6, 0xa5, 0x76, 0xb4, 0x5d, 0xed, 0x68, 0x5f, 0x6b, 0x47, 0xfb, 0x59, 0x3b,
0xda, 0xc2, 0x90, 0xdd, 0x2f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x98, 0x18, 0x12, 0xde, 0x23,
0x03, 0x00, 0x00,
// 487 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x52, 0x4d, 0x6f, 0xda, 0x40,
0x10, 0x8d, 0x21, 0x7c, 0x74, 0x88, 0x51, 0xb5, 0x8a, 0x90, 0x63, 0x52, 0x87, 0xfa, 0x94, 0x93,
0x51, 0xda, 0x4b, 0x0f, 0x95, 0x2a, 0xa5, 0xe1, 0x50, 0xa9, 0x07, 0x64, 0x7e, 0x40, 0x04, 0x78,
0x0a, 0x2b, 0x81, 0xd7, 0x5d, 0x8f, 0x69, 0xb8, 0xf5, 0xe7, 0xe5, 0xd8, 0x43, 0x55, 0xf5, 0x54,
0x15, 0xff, 0x82, 0xfe, 0x84, 0x6a, 0x77, 0xed, 0x24, 0x40, 0xb8, 0xed, 0x9b, 0xf7, 0x76, 0xf7,
0xcd, 0x9b, 0x01, 0x48, 0xe7, 0x7c, 0x19, 0x24, 0x52, 0x90, 0x60, 0xf6, 0x54, 0xc4, 0x34, 0xe6,
0x31, 0xca, 0x28, 0x58, 0x5d, 0xb9, 0xdd, 0x99, 0x10, 0xb3, 0x05, 0xf6, 0x35, 0x39, 0xc9, 0xbe,
0xf4, 0x71, 0x99, 0xd0, 0xda, 0x68, 0xdd, 0xd3, 0x99, 0x98, 0x09, 0x7d, 0xec, 0xab, 0x93, 0xa9,
0xfa, 0xbf, 0x2c, 0xb0, 0x3f, 0x4a, 0x1c, 0x13, 0x86, 0xf8, 0x35, 0xc3, 0x94, 0x58, 0x07, 0x2a,
0x3c, 0x72, 0xac, 0x9e, 0x75, 0xf9, 0xe2, 0xba, 0x9e, 0xff, 0xb9, 0xa8, 0x7c, 0xba, 0x09, 0x2b,
0x3c, 0x62, 0x1d, 0xa8, 0x4f, 0xb2, 0x38, 0x5a, 0xa0, 0x53, 0x51, 0x5c, 0x58, 0x20, 0xe6, 0x40,
0x43, 0x66, 0x31, 0xf1, 0x25, 0x3a, 0x55, 0x4d, 0x94, 0x90, 0x9d, 0x41, 0x33, 0x16, 0xb7, 0x09,
0x5f, 0x09, 0x72, 0x8e, 0x7b, 0xd6, 0x65, 0x33, 0x6c, 0xc4, 0x62, 0xa8, 0x20, 0x73, 0xa1, 0x49,
0x28, 0x97, 0x3c, 0x1e, 0x2f, 0x9c, 0x9a, 0xa6, 0x1e, 0x30, 0x3b, 0x85, 0x5a, 0x4a, 0x11, 0x8f,
0x9d, 0xba, 0x7e, 0xce, 0x00, 0xf5, 0x7d, 0x4a, 0x91, 0xc8, 0xc8, 0x69, 0x98, 0xef, 0x0d, 0x2a,
0xea, 0x28, 0xa5, 0xd3, 0x7c, 0xa8, 0xa3, 0x94, 0xbe, 0x0f, 0xed, 0xb2, 0xaf, 0x34, 0x11, 0x71,
0x8a, 0xec, 0x25, 0x54, 0x93, 0xa2, 0x33, 0x3b, 0x54, 0x47, 0xbf, 0x0d, 0x27, 0x23, 0x1a, 0x4b,
0x2a, 0x5a, 0xf7, 0x5f, 0x83, 0x7d, 0x83, 0x0b, 0x7c, 0xcc, 0x62, 0xff, 0xca, 0x15, 0xb4, 0x4b,
0x49, 0xf1, 0xec, 0x05, 0xb4, 0xf0, 0x8e, 0xd3, 0x6d, 0x4a, 0x63, 0xca, 0xd2, 0x42, 0x0b, 0xaa,
0x34, 0xd2, 0x15, 0xdf, 0x86, 0xd6, 0xe0, 0x0e, 0xa7, 0xe5, 0x27, 0x3d, 0x38, 0x31, 0xf0, 0xa0,
0xad, 0xcf, 0x00, 0x43, 0x5a, 0x1f, 0xf4, 0xa0, 0x02, 0xfa, 0xc6, 0x23, 0x9a, 0xeb, 0x41, 0xd8,
0xa1, 0x01, 0x2a, 0x88, 0x39, 0xf2, 0xd9, 0x9c, 0xf4, 0x18, 0xec, 0xb0, 0x40, 0x6f, 0x7e, 0x56,
0xa0, 0x35, 0x9a, 0xf3, 0xe5, 0x08, 0xe5, 0x8a, 0x4f, 0x91, 0x0d, 0xa0, 0x6e, 0x82, 0x61, 0xe7,
0xc1, 0xd6, 0xfa, 0x04, 0x5b, 0x7b, 0xe0, 0xbe, 0x3a, 0xc0, 0x16, 0xb6, 0xdf, 0x43, 0x4d, 0x67,
0xc7, 0xba, 0x3b, 0xba, 0xa7, 0x89, 0xba, 0x9d, 0xc0, 0xac, 0x64, 0x50, 0xae, 0x64, 0x30, 0x50,
0x2b, 0xa9, 0x4c, 0x98, 0x18, 0xf7, 0x4c, 0x6c, 0x0d, 0x60, 0xcf, 0xc4, 0x4e, 0xf6, 0x1f, 0xe0,
0x58, 0x65, 0xc9, 0xdc, 0x1d, 0xd9, 0x93, 0xbc, 0xdd, 0xee, 0xb3, 0x5c, 0xf1, 0xc0, 0x3b, 0xa8,
0x0e, 0x69, 0xcd, 0xce, 0x76, 0x34, 0x8f, 0xf1, 0x1f, 0xea, 0xe0, 0xfa, 0xfc, 0x7e, 0xe3, 0x1d,
0xfd, 0xde, 0x78, 0x47, 0xff, 0x36, 0x9e, 0xf5, 0x3d, 0xf7, 0xac, 0xfb, 0xdc, 0xb3, 0x7e, 0xe4,
0x9e, 0xf5, 0x37, 0xf7, 0xac, 0x49, 0x5d, 0xab, 0xdf, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff,
0xb1, 0x72, 0x31, 0xad, 0x03, 0x00, 0x00,
}

View file

@ -17,6 +17,11 @@ message CreateRequest {
string id = 1 [(gogoproto.customname) = "ID"];
string bundle = 2;
string runtime = 3;
bool no_pivot = 4;
bool terminal = 5;
string stdin = 6;
string stdout = 7;
string stderr = 8;
}
message CreateResponse {
@ -27,7 +32,7 @@ message StartRequest {
}
message DeleteRequest {
uint32 pid = 1;
}
message DeleteResponse {
@ -43,7 +48,7 @@ message ExecResponse {
}
message PtyRequest {
string id = 1 [(gogoproto.customname) = "ID"];
uint32 pid = 1;
uint32 width = 2;
uint32 height = 3;
}

View file

@ -0,0 +1,38 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
"time"
)
type checkpoint struct {
// Timestamp is the time that checkpoint happened
Created time.Time `json:"created"`
// Name is the name of the checkpoint
Name string `json:"name"`
// TCP checkpoints open tcp connections
TCP bool `json:"tcp"`
// UnixSockets persists unix sockets in the checkpoint
UnixSockets bool `json:"unixSockets"`
// Shell persists tty sessions in the checkpoint
Shell bool `json:"shell"`
// Exit exits the container after the checkpoint is finished
Exit bool `json:"exit"`
// EmptyNS tells CRIU not to restore a particular namespace
EmptyNS []string `json:"emptyNS,omitempty"`
}
func loadCheckpoint(checkpointPath string) (*checkpoint, error) {
f, err := os.Open(filepath.Join(checkpointPath, "config.json"))
if err != nil {
return nil, err
}
defer f.Close()
var cpt checkpoint
if err := json.NewDecoder(f).Decode(&cpt); err != nil {
return nil, err
}
return &cpt, nil
}

View file

@ -1,82 +0,0 @@
// +build !solaris
package main
import (
"fmt"
"os"
"syscall"
"unsafe"
)
// NewConsole returns an initialized console that can be used within a container by copying bytes
// from the master side to the slave that is attached as the tty for the container's init process.
func newConsole(uid, gid int) (*os.File, string, error) {
master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
if err != nil {
return nil, "", err
}
if err = saneTerminal(master); err != nil {
return nil, "", err
}
console, err := ptsname(master)
if err != nil {
return nil, "", err
}
if err := unlockpt(master); err != nil {
return nil, "", err
}
if err := os.Chmod(console, 0600); err != nil {
return nil, "", err
}
if err := os.Chown(console, uid, gid); err != nil {
return nil, "", err
}
return master, console, nil
}
// saneTerminal sets the necessary tty_ioctl(4)s to ensure that a pty pair
// created by us acts normally. In particular, a not-very-well-known default of
// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
// problem for terminal emulators, because we relay data from the terminal we
// also relay that funky line discipline.
func saneTerminal(terminal *os.File) error {
// Go doesn't have a wrapper for any of the termios ioctls.
var termios syscall.Termios
if err := ioctl(terminal.Fd(), syscall.TCGETS, uintptr(unsafe.Pointer(&termios))); err != nil {
return fmt.Errorf("ioctl(tty, tcgets): %s", err.Error())
}
// Set -onlcr so we don't have to deal with \r.
termios.Oflag &^= syscall.ONLCR
if err := ioctl(terminal.Fd(), syscall.TCSETS, uintptr(unsafe.Pointer(&termios))); err != nil {
return fmt.Errorf("ioctl(tty, tcsets): %s", err.Error())
}
return nil
}
func ioctl(fd uintptr, flag, data uintptr) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 {
return err
}
return nil
}
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f *os.File) error {
var u int32
return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u)))
}
// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f *os.File) (string, error) {
var n int32
if err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil {
return "", err
}
return fmt.Sprintf("/dev/pts/%d", n), nil
}

View file

@ -1,14 +0,0 @@
// +build solaris
package main
import (
"errors"
"os"
)
// NewConsole returns an initialized console that can be used within a container by copying bytes
// from the master side to the slave that is attached as the tty for the container's init process.
func newConsole(uid, gid int) (*os.File, string, error) {
return nil, "", errors.New("newConsole not implemented on Solaris")
}

View file

@ -0,0 +1,5 @@
package main
func newExecProcess(id, bundle, runtimeName string) (process, error) {
return nil, nil
}

122
cmd/containerd-shim/init.go Normal file
View file

@ -0,0 +1,122 @@
package main
import (
"context"
"os"
"path/filepath"
"sync"
"syscall"
runc "github.com/crosbymichael/go-runc"
"github.com/docker/containerd/api/shim"
)
type initProcess struct {
sync.WaitGroup
id string
bundle string
console *runc.Console
io runc.IO
runc *runc.Runc
status int
pid int
}
func newInitProcess(context context.Context, r *shim.CreateRequest) (process, error) {
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
runtime := &runc.Runc{
Command: r.Runtime,
Log: filepath.Join(cwd, "log.json"),
LogFormat: runc.JSON,
PdeathSignal: syscall.SIGKILL,
}
p := &initProcess{
id: r.ID,
bundle: r.Bundle,
runc: runtime,
}
var (
socket *runc.ConsoleSocket
io runc.IO
)
if r.Terminal {
if socket, err = runc.NewConsoleSocket(filepath.Join(cwd, "pty.sock")); err != nil {
return nil, err
}
} else {
// TODO: get uid/gid
if io, err = runc.NewPipeIO(0, 0); err != nil {
return nil, err
}
}
opts := &runc.CreateOpts{
PidFile: filepath.Join(cwd, "pid"),
ConsoleSocket: socket,
IO: io,
NoPivot: r.NoPivot,
}
if err := p.runc.Create(context, r.ID, r.Bundle, opts); err != nil {
return nil, err
}
if socket != nil {
console, err := socket.ReceiveMaster()
if err != nil {
return nil, err
}
p.console = console
if err := copyConsole(context, console, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup); err != nil {
return nil, err
}
} else {
if err := copyPipes(context, io, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup); err != nil {
return nil, err
}
}
pid, err := runc.ReadPidFile(opts.PidFile)
if err != nil {
return nil, err
}
p.pid = pid
return p, nil
}
func (p *initProcess) Pid() int {
return p.pid
}
func (p *initProcess) Status() int {
return p.status
}
func (p *initProcess) Start(context context.Context) error {
return p.runc.Start(context, p.id)
}
func (p *initProcess) Exited(status int) {
p.status = status
}
func (p *initProcess) Delete(context context.Context) error {
p.killAll(context)
p.Wait()
err := p.runc.Delete(context, p.id)
p.io.Close()
return err
}
func (p *initProcess) Resize(ws runc.WinSize) error {
if p.console == nil {
return nil
}
return p.console.Resize(ws)
}
func (p *initProcess) killAll(context context.Context) error {
return p.runc.Kill(context, p.id, int(syscall.SIGKILL), &runc.KillOpts{
All: true,
})
}

View file

@ -52,7 +52,9 @@ func main() {
}
var (
server = grpc.NewServer()
sv = &service{}
sv = &service{
processes: make(map[int]process),
}
)
shim.RegisterShimServiceServer(server, sv)
l, err := utils.CreateUnixSocket("shim.sock")

View file

@ -1,301 +1,25 @@
package main
import (
"encoding/json"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"sync"
"syscall"
"time"
runc "github.com/crosbymichael/go-runc"
)
var errRuntime = errors.New("shim: runtime execution error")
type checkpoint struct {
// Timestamp is the time that checkpoint happened
Created time.Time `json:"created"`
// Name is the name of the checkpoint
Name string `json:"name"`
// TCP checkpoints open tcp connections
TCP bool `json:"tcp"`
// UnixSockets persists unix sockets in the checkpoint
UnixSockets bool `json:"unixSockets"`
// Shell persists tty sessions in the checkpoint
Shell bool `json:"shell"`
// Exit exits the container after the checkpoint is finished
Exit bool `json:"exit"`
// EmptyNS tells CRIU not to restore a particular namespace
EmptyNS []string `json:"emptyNS,omitempty"`
}
/*
type processState struct {
Terminal bool `json:"terminal"`
Exec bool `json:"exec"`
Stdin string `json:"containerdStdin"`
Stdout string `json:"containerdStdout"`
Stderr string `json:"containerdStderr"`
RuntimeArgs []string `json:"runtimeArgs"`
NoPivotRoot bool `json:"noPivotRoot"`
CheckpointPath string `json:"checkpoint"`
RootUID int `json:"rootUID"`
RootGID int `json:"rootGID"`
}
*/
type process struct {
sync.WaitGroup
id string
bundle string
stdio *stdio
exec bool
containerPid int
checkpoint *checkpoint
checkpointPath string
shimIO *IO
stdinCloser io.Closer
console *os.File
consolePath string
runtime string
exitStatus int
Stdin string `json:"containerdStdin"`
Stdout string `json:"containerdStdout"`
Stderr string `json:"containerdStderr"`
Terminal bool `json:"terminal"`
RootUID int `json:"rootUID"`
RootGID int `json:"rootGID"`
}
func newProcess(id, bundle, runtimeName string) (*process, error) {
p := &process{
id: id,
bundle: bundle,
runtime: runtimeName,
}
if err := p.openIO(); err != nil {
return nil, err
}
return p, nil
}
func loadCheckpoint(checkpointPath string) (*checkpoint, error) {
f, err := os.Open(filepath.Join(checkpointPath, "config.json"))
if err != nil {
return nil, err
}
defer f.Close()
var cpt checkpoint
if err := json.NewDecoder(f).Decode(&cpt); err != nil {
return nil, err
}
return &cpt, nil
}
func (p *process) create(isExec bool) error {
cwd, err := os.Getwd()
if err != nil {
return err
}
logPath := filepath.Join(cwd, "log.json")
args := []string{
"--log", logPath,
"--log-format", "json",
}
if isExec {
args = append(args, "exec",
"-d",
"--process", filepath.Join(cwd, "process.json"),
"--console-socket", p.consolePath,
)
} else if p.checkpoint != nil {
args = append(args, "restore",
"-d",
"--image-path", p.checkpointPath,
"--work-path", filepath.Join(p.checkpointPath, "criu.work", "restore-"+time.Now().Format(time.RFC3339)),
)
add := func(flags ...string) {
args = append(args, flags...)
}
if p.checkpoint.Shell {
add("--shell-job")
}
if p.checkpoint.TCP {
add("--tcp-established")
}
if p.checkpoint.UnixSockets {
add("--ext-unix-sk")
}
/*
if p.state.NoPivotRoot {
add("--no-pivot")
}
*/
for _, ns := range p.checkpoint.EmptyNS {
add("--empty-ns", ns)
}
} else {
args = append(args, "create",
"--bundle", p.bundle,
"--console-socket", p.consolePath,
)
/*
if p.state.NoPivotRoot {
args = append(args, "--no-pivot")
}
*/
}
args = append(args,
"--pid-file", filepath.Join(cwd, "pid"),
p.id,
)
cmd := exec.Command(p.runtime, args...)
cmd.Dir = p.bundle
if p.stdio != nil {
cmd.Stdin = p.stdio.stdin
cmd.Stdout = p.stdio.stdout
cmd.Stderr = p.stdio.stderr
}
// Call out to setPDeathSig to set SysProcAttr as elements are platform specific
cmd.SysProcAttr = setPDeathSig()
if err := cmd.Start(); err != nil {
if exErr, ok := err.(*exec.Error); ok {
if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist {
return fmt.Errorf("%s not installed on system", p.runtime)
}
}
return err
}
if runtime.GOOS != "solaris" {
// Since current logic dictates that we need a pid at the end of p.create
// we need to call runtime start as well on Solaris hence we need the
// pipes to stay open.
if p.stdio != nil {
p.stdio.stdout.Close()
p.stdio.stderr.Close()
}
}
if err := cmd.Wait(); err != nil {
if _, ok := err.(*exec.ExitError); ok {
return errRuntime
}
return err
}
data, err := ioutil.ReadFile("pid")
if err != nil {
return err
}
pid, err := strconv.Atoi(string(data))
if err != nil {
return err
}
p.containerPid = pid
return nil
}
func (p *process) pid() int {
return p.containerPid
}
func (p *process) delete() error {
cmd := exec.Command(p.runtime, "delete", p.id)
cmd.SysProcAttr = setPDeathSig()
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("%s: %v", out, err)
}
return nil
}
// IO holds all 3 standard io Reader/Writer (stdin,stdout,stderr)
type IO struct {
Stdin io.WriteCloser
Stdout io.ReadCloser
Stderr io.ReadCloser
}
func (p *process) initializeIO(rootuid int) (i *IO, err error) {
var fds []uintptr
i = &IO{}
// cleanup in case of an error
defer func() {
if err != nil {
for _, fd := range fds {
syscall.Close(int(fd))
}
}
}()
// STDIN
r, w, err := os.Pipe()
if err != nil {
return nil, err
}
fds = append(fds, r.Fd(), w.Fd())
p.stdio.stdin, i.Stdin = r, w
// STDOUT
if r, w, err = os.Pipe(); err != nil {
return nil, err
}
fds = append(fds, r.Fd(), w.Fd())
p.stdio.stdout, i.Stdout = w, r
// STDERR
if r, w, err = os.Pipe(); err != nil {
return nil, err
}
fds = append(fds, r.Fd(), w.Fd())
p.stdio.stderr, i.Stderr = w, r
// change ownership of the pipes in case we are in a user namespace
for _, fd := range fds {
if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil {
return nil, err
}
}
return i, nil
}
func (p *process) Close() error {
if p.stdio == nil {
return nil
}
return p.stdio.Close()
}
func (p *process) start() error {
cmd := exec.Command(p.runtime, "start", p.id)
cmd.SysProcAttr = setPDeathSig()
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("%s: %v", out, err)
}
return nil
}
func (p *process) setExited(status int) {
p.exitStatus = status
}
type stdio struct {
stdin *os.File
stdout *os.File
stderr *os.File
}
func (s *stdio) Close() error {
err := s.stdin.Close()
if oerr := s.stdout.Close(); err == nil {
err = oerr
}
if oerr := s.stderr.Close(); err == nil {
err = oerr
}
return err
type process interface {
// Pid returns the pid for the process
Pid() int
// Start starts the user's defined process inside
Start(context.Context) error
// Delete deletes the process and closes all open pipes
Delete(context.Context) error
// Resize resizes the process console
Resize(ws runc.WinSize) error
// Exited sets the exit status for the process
Exited(status int)
// Status returns the exit status
Status() int
}

View file

@ -1,95 +1,57 @@
// +build !solaris
package main
import (
"context"
"fmt"
"io"
"os/exec"
"sync"
"syscall"
"time"
runc "github.com/crosbymichael/go-runc"
"github.com/tonistiigi/fifo"
"golang.org/x/net/context"
)
// setPDeathSig sets the parent death signal to SIGKILL so that if the
// shim dies the container process also dies.
func setPDeathSig() *syscall.SysProcAttr {
return &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
func copyConsole(ctx context.Context, console *runc.Console, stdin, stdout, stderr string, wg *sync.WaitGroup) error {
in, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0)
if err != nil {
return err
}
go io.Copy(console, in)
outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0)
if err != nil {
return err
}
outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0)
if err != nil {
return err
}
wg.Add(1)
go func() {
io.Copy(outw, console)
console.Close()
outr.Close()
outw.Close()
wg.Done()
}()
return nil
}
// openIO opens the pre-created fifo's for use with the container
// in RDWR so that they remain open if the other side stops listening
func (p *process) openIO() error {
return nil
p.stdio = &stdio{}
var (
uid = p.RootUID
gid = p.RootGID
)
ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)
stdinCloser, err := fifo.OpenFifo(ctx, p.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return err
}
p.stdinCloser = stdinCloser
if p.Terminal {
master, console, err := newConsole(uid, gid)
if err != nil {
return err
}
p.console = master
p.consolePath = console
stdin, err := fifo.OpenFifo(ctx, p.Stdin, syscall.O_RDONLY, 0)
if err != nil {
return err
}
go io.Copy(master, stdin)
stdoutw, err := fifo.OpenFifo(ctx, p.Stdout, syscall.O_WRONLY, 0)
if err != nil {
return err
}
stdoutr, err := fifo.OpenFifo(ctx, p.Stdout, syscall.O_RDONLY, 0)
if err != nil {
return err
}
p.Add(1)
go func() {
io.Copy(stdoutw, master)
master.Close()
stdoutr.Close()
stdoutw.Close()
p.Done()
}()
return nil
}
i, err := p.initializeIO(uid)
if err != nil {
return err
}
p.shimIO = i
// non-tty
func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg *sync.WaitGroup) error {
for name, dest := range map[string]func(wc io.WriteCloser, rc io.Closer){
p.Stdout: func(wc io.WriteCloser, rc io.Closer) {
p.Add(1)
stdout: func(wc io.WriteCloser, rc io.Closer) {
wg.Add(1)
go func() {
io.Copy(wc, i.Stdout)
p.Done()
io.Copy(wc, rio.Stdout())
wg.Done()
wc.Close()
rc.Close()
}()
},
p.Stderr: func(wc io.WriteCloser, rc io.Closer) {
p.Add(1)
stderr: func(wc io.WriteCloser, rc io.Closer) {
wg.Add(1)
go func() {
io.Copy(wc, i.Stderr)
p.Done()
io.Copy(wc, rio.Stderr())
wg.Done()
wc.Close()
rc.Close()
}()
@ -106,25 +68,14 @@ func (p *process) openIO() error {
dest(fw, fr)
}
f, err := fifo.OpenFifo(ctx, p.Stdin, syscall.O_RDONLY, 0)
f, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0)
if err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", p.Stdin, err)
return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err)
}
go func() {
io.Copy(i.Stdin, f)
i.Stdin.Close()
io.Copy(rio.Stdin(), f)
rio.Stdin().Close()
f.Close()
}()
return nil
}
func (p *process) killAll() error {
cmd := exec.Command(p.runtime, "kill", "--all", p.id, "SIGKILL")
cmd.SysProcAttr = setPDeathSig()
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("%s: %v", out, err)
}
return nil
}

View file

@ -1,70 +0,0 @@
// +build solaris
package main
import (
"io"
"os"
"syscall"
)
// setPDeathSig is a no-op on Solaris as Pdeathsig is not defined.
func setPDeathSig() *syscall.SysProcAttr {
return nil
}
// TODO: Update to using fifo's package in openIO. Need to
// 1. Merge and vendor changes in the package to use sys/unix.
// 2. Figure out why context.Background is timing out.
// openIO opens the pre-created fifo's for use with the container
// in RDWR so that they remain open if the other side stops listening
func (p *process) openIO() error {
p.stdio = &stdio{}
var (
uid = p.state.RootUID
)
i, err := p.initializeIO(uid)
if err != nil {
return err
}
p.shimIO = i
// Both tty and non-tty mode are handled by the runtime using
// the following pipes
for name, dest := range map[string]func(f *os.File){
p.state.Stdout: func(f *os.File) {
p.Add(1)
go func() {
io.Copy(f, i.Stdout)
p.Done()
}()
},
p.state.Stderr: func(f *os.File) {
p.Add(1)
go func() {
io.Copy(f, i.Stderr)
p.Done()
}()
},
} {
f, err := os.OpenFile(name, syscall.O_RDWR, 0)
if err != nil {
return err
}
dest(f)
}
f, err := os.OpenFile(p.state.Stdin, syscall.O_RDONLY, 0)
if err != nil {
return err
}
go func() {
io.Copy(i.Stdin, f)
i.Stdin.Close()
}()
return nil
}
func (p *process) killAll() error {
return nil
}

View file

@ -1,9 +1,12 @@
package main
import (
"fmt"
"sync"
runc "github.com/crosbymichael/go-runc"
"github.com/docker/containerd/api/shim"
"github.com/docker/containerd/utils"
"github.com/docker/docker/pkg/term"
google_protobuf "github.com/golang/protobuf/ptypes/empty"
"golang.org/x/net/context"
)
@ -11,43 +14,51 @@ import (
var emptyResponse = &google_protobuf.Empty{}
type service struct {
init *process
initPid int
mu sync.Mutex
processes map[int]process
}
func (s *service) Create(ctx context.Context, r *shim.CreateRequest) (*shim.CreateResponse, error) {
process, err := newProcess(r.ID, r.Bundle, r.Runtime)
process, err := newInitProcess(ctx, r)
if err != nil {
return nil, err
}
s.init = process
if err := process.create(false); err != nil {
return nil, err
}
s.mu.Lock()
pid := process.Pid()
s.initPid, s.processes[pid] = pid, process
s.mu.Unlock()
return &shim.CreateResponse{
Pid: uint32(process.pid()),
Pid: uint32(pid),
}, nil
}
func (s *service) Start(ctx context.Context, r *shim.StartRequest) (*google_protobuf.Empty, error) {
if err := s.init.start(); err != nil {
s.mu.Lock()
p := s.processes[s.initPid]
s.mu.Unlock()
if err := p.Start(ctx); err != nil {
return nil, err
}
return emptyResponse, nil
}
func (s *service) Delete(ctx context.Context, r *shim.DeleteRequest) (*shim.DeleteResponse, error) {
// TODO: error when container has not stopped
err := s.init.killAll()
s.init.Wait()
if derr := s.init.delete(); err == nil {
err = derr
s.mu.Lock()
p, ok := s.processes[int(r.Pid)]
s.mu.Unlock()
if !ok {
return nil, fmt.Errorf("process does not exist %d", r.Pid)
}
if cerr := s.init.Close(); err == nil {
err = cerr
if err := p.Delete(ctx); err != nil {
return nil, err
}
s.mu.Lock()
delete(s.processes, int(r.Pid))
s.mu.Unlock()
return &shim.DeleteResponse{
ExitStatus: uint32(s.init.exitStatus),
}, err
ExitStatus: uint32(p.Status()),
}, nil
}
func (s *service) Exec(ctx context.Context, r *shim.ExecRequest) (*shim.ExecResponse, error) {
@ -55,22 +66,27 @@ func (s *service) Exec(ctx context.Context, r *shim.ExecRequest) (*shim.ExecResp
}
func (s *service) Pty(ctx context.Context, r *shim.PtyRequest) (*google_protobuf.Empty, error) {
if s.init.console == nil {
return emptyResponse, nil
}
ws := term.Winsize{
ws := runc.WinSize{
Width: uint16(r.Width),
Height: uint16(r.Height),
}
if err := term.SetWinsize(s.init.console.Fd(), &ws); err != nil {
s.mu.Lock()
p, ok := s.processes[int(r.Pid)]
s.mu.Unlock()
if !ok {
return nil, fmt.Errorf("process does not exist %d", r.Pid)
}
if err := p.Resize(ws); err != nil {
return nil, err
}
return emptyResponse, nil
}
func (s *service) processExited(e utils.Exit) error {
if s.init.pid() == e.Pid {
s.init.setExited(e.Status)
s.mu.Lock()
if p, ok := s.processes[e.Pid]; ok {
p.Exited(e.Status)
}
s.mu.Unlock()
return nil
}