Update shim for exec

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2016-02-01 11:02:41 -08:00
parent 6808dbc02f
commit 835f3b6a97
37 changed files with 786 additions and 709 deletions

View file

@ -2,6 +2,7 @@ package server
import ( import (
"errors" "errors"
"fmt"
"syscall" "syscall"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -75,18 +76,27 @@ func (s *apiServer) AddProcess(ctx context.Context, r *types.AddProcessRequest)
AdditionalGids: r.User.AdditionalGids, AdditionalGids: r.User.AdditionalGids,
}, },
} }
if r.Id == "" {
return nil, fmt.Errorf("container id cannot be empty")
}
if r.Pid == "" {
return nil, fmt.Errorf("process id cannot be empty")
}
e := supervisor.NewEvent(supervisor.AddProcessEventType) e := supervisor.NewEvent(supervisor.AddProcessEventType)
e.ID = r.Id e.ID = r.Id
e.Pid = r.Pid
e.ProcessSpec = process e.ProcessSpec = process
e.Console = r.Console e.StartResponse = make(chan supervisor.StartResponse, 1)
e.Stdin = r.Stdin
e.Stdout = r.Stdout
e.Stderr = r.Stderr
s.sv.SendEvent(e) s.sv.SendEvent(e)
if err := <-e.Err; err != nil { if err := <-e.Err; err != nil {
return nil, err return nil, err
} }
return &types.AddProcessResponse{}, nil sr := <-e.StartResponse
return &types.AddProcessResponse{
Stdin: sr.Stdin,
Stdout: sr.Stdout,
Stderr: sr.Stderr,
}, nil
} }
func (s *apiServer) CreateCheckpoint(ctx context.Context, r *types.CreateCheckpointRequest) (*types.CreateCheckpointResponse, error) { func (s *apiServer) CreateCheckpoint(ctx context.Context, r *types.CreateCheckpointRequest) (*types.CreateCheckpointResponse, error) {

View file

@ -65,7 +65,7 @@ var _ = math.Inf
type CreateContainerRequest struct { type CreateContainerRequest struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
BundlePath string `protobuf:"bytes,2,opt,name=bundlePath" json:"bundlePath,omitempty"` BundlePath string `protobuf:"bytes,2,opt,name=bundlePath" json:"bundlePath,omitempty"`
Checkpoint string `protobuf:"bytes,3,opt,name=checkpoint" json:"checkpoint,omitempty"` Checkpoint string `protobuf:"bytes,7,opt,name=checkpoint" json:"checkpoint,omitempty"`
} }
func (m *CreateContainerRequest) Reset() { *m = CreateContainerRequest{} } func (m *CreateContainerRequest) Reset() { *m = CreateContainerRequest{} }
@ -74,9 +74,10 @@ func (*CreateContainerRequest) ProtoMessage() {}
func (*CreateContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*CreateContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type CreateContainerResponse struct { type CreateContainerResponse struct {
Stdin string `protobuf:"bytes,1,opt,name=stdin" json:"stdin,omitempty"` Pid uint32 `protobuf:"varint,1,opt,name=pid" json:"pid,omitempty"`
Stdout string `protobuf:"bytes,2,opt,name=stdout" json:"stdout,omitempty"` Stdin string `protobuf:"bytes,2,opt,name=stdin" json:"stdin,omitempty"`
Stderr string `protobuf:"bytes,3,opt,name=stderr" json:"stderr,omitempty"` Stdout string `protobuf:"bytes,3,opt,name=stdout" json:"stdout,omitempty"`
Stderr string `protobuf:"bytes,4,opt,name=stderr" json:"stderr,omitempty"`
} }
func (m *CreateContainerResponse) Reset() { *m = CreateContainerResponse{} } func (m *CreateContainerResponse) Reset() { *m = CreateContainerResponse{} }
@ -110,10 +111,7 @@ type AddProcessRequest struct {
Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"`
Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"`
Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"` Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"`
Stdin string `protobuf:"bytes,7,opt,name=stdin" json:"stdin,omitempty"` Pid string `protobuf:"bytes,7,opt,name=pid" json:"pid,omitempty"`
Stdout string `protobuf:"bytes,8,opt,name=stdout" json:"stdout,omitempty"`
Stderr string `protobuf:"bytes,9,opt,name=stderr" json:"stderr,omitempty"`
Console string `protobuf:"bytes,10,opt,name=console" json:"console,omitempty"`
} }
func (m *AddProcessRequest) Reset() { *m = AddProcessRequest{} } func (m *AddProcessRequest) Reset() { *m = AddProcessRequest{} }
@ -140,6 +138,9 @@ func (*User) ProtoMessage() {}
func (*User) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*User) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
type AddProcessResponse struct { type AddProcessResponse struct {
Stdin string `protobuf:"bytes,1,opt,name=stdin" json:"stdin,omitempty"`
Stdout string `protobuf:"bytes,2,opt,name=stdout" json:"stdout,omitempty"`
Stderr string `protobuf:"bytes,3,opt,name=stderr" json:"stderr,omitempty"`
} }
func (m *AddProcessResponse) Reset() { *m = AddProcessResponse{} } func (m *AddProcessResponse) Reset() { *m = AddProcessResponse{} }
@ -1084,94 +1085,94 @@ var _API_serviceDesc = grpc.ServiceDesc{
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 1440 bytes of a gzipped FileDescriptorProto // 1440 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x58, 0xd9, 0x72, 0xdc, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x58, 0xdb, 0x72, 0xdc, 0x44,
0x17, 0xf6, 0xec, 0x33, 0x67, 0x16, 0xdb, 0xf2, 0x92, 0xf1, 0xfc, 0x7f, 0x88, 0x11, 0x81, 0xa4, 0x13, 0xf6, 0x9e, 0x77, 0x7b, 0x0f, 0xb6, 0xe5, 0xd8, 0x59, 0xef, 0xff, 0x87, 0x04, 0x11, 0x48,
0xa8, 0x94, 0x2b, 0x38, 0x2c, 0x21, 0x5c, 0x40, 0x70, 0x52, 0x09, 0x54, 0x02, 0xae, 0xc4, 0xa6, 0x8a, 0x4a, 0xb9, 0x82, 0xc3, 0x21, 0x84, 0x0b, 0x08, 0x4e, 0x2a, 0x81, 0x4a, 0xc0, 0x95, 0xd8,
0x8a, 0x1b, 0xa6, 0x64, 0xa9, 0x19, 0x8b, 0xd1, 0x48, 0x42, 0x6a, 0x79, 0x79, 0x05, 0x9e, 0x87, 0x54, 0x71, 0xc3, 0x96, 0x2c, 0x0d, 0x6b, 0xb1, 0x3a, 0x21, 0x8d, 0x7c, 0xb8, 0xe4, 0x96, 0x07,
0xe2, 0x01, 0xa8, 0xe2, 0x9e, 0xe7, 0xe0, 0x29, 0x38, 0xdd, 0x7d, 0xd4, 0x5a, 0x66, 0x09, 0x5c, 0xe2, 0x01, 0xa8, 0xe2, 0x9e, 0xe7, 0xe0, 0x29, 0x68, 0xcd, 0xb4, 0x46, 0x23, 0xed, 0xae, 0x03,
0x70, 0x33, 0x55, 0xdd, 0x7d, 0xce, 0x77, 0xbe, 0xb3, 0xaa, 0x7b, 0xa0, 0x63, 0x85, 0xee, 0x41, 0x17, 0xdc, 0xb8, 0x6a, 0x46, 0xdd, 0x5f, 0x7f, 0xfd, 0x75, 0xf7, 0xec, 0x8c, 0xa1, 0x67, 0x45,
0x18, 0x05, 0x3c, 0x30, 0x1a, 0xfc, 0x3a, 0x64, 0xb1, 0xf9, 0x02, 0x76, 0x8f, 0x22, 0x66, 0x71, 0xee, 0x5e, 0x14, 0x87, 0x3c, 0x34, 0x5a, 0xfc, 0x32, 0x62, 0x89, 0xf9, 0x02, 0x76, 0x0e, 0x62,
0x76, 0x14, 0xf8, 0xdc, 0x72, 0x7d, 0x16, 0xbd, 0x62, 0x3f, 0x27, 0x2c, 0xe6, 0x06, 0x40, 0xd5, 0x66, 0x71, 0x76, 0x10, 0x06, 0xdc, 0x72, 0x03, 0x16, 0xbf, 0x62, 0x3f, 0xa7, 0x2c, 0xe1, 0x06,
0x75, 0x86, 0x95, 0xfd, 0xca, 0xdd, 0x8e, 0x81, 0x8b, 0xb3, 0xc4, 0x77, 0x3c, 0x76, 0x6c, 0xf1, 0x40, 0xdd, 0x75, 0xc6, 0xb5, 0x5b, 0xb5, 0xbb, 0x3d, 0x03, 0x17, 0x27, 0x69, 0xe0, 0x78, 0xec,
0xf3, 0x61, 0x35, 0xdd, 0xb3, 0xcf, 0x99, 0x3d, 0x0d, 0x03, 0xd7, 0xe7, 0xc3, 0x9a, 0xd8, 0x33, 0xd0, 0xe2, 0xa7, 0xe3, 0x7a, 0xbe, 0x67, 0x9f, 0x32, 0x7b, 0x1e, 0x85, 0x6e, 0xc0, 0xc7, 0x9d,
0x9f, 0xc3, 0x8d, 0x39, 0xb4, 0x38, 0x0c, 0xfc, 0x98, 0x19, 0x7d, 0x68, 0xc4, 0xdc, 0x71, 0x7d, 0x6c, 0xcf, 0x3c, 0x86, 0xeb, 0x0b, 0x68, 0x49, 0x14, 0x06, 0x09, 0x33, 0xfa, 0xd0, 0x88, 0x08,
0x42, 0x1c, 0x40, 0x13, 0x97, 0x41, 0xc2, 0x09, 0x4d, 0xad, 0x59, 0x14, 0x11, 0xd2, 0x43, 0xe8, 0x6f, 0x68, 0x0c, 0xa1, 0x95, 0x70, 0xc7, 0x0d, 0x08, 0x6a, 0x04, 0x6d, 0x5c, 0x86, 0x29, 0x1f,
0xbf, 0x76, 0x27, 0xbe, 0xe5, 0x2d, 0xa2, 0xd3, 0x85, 0x5a, 0x88, 0x8b, 0x4c, 0x53, 0x4a, 0x4a, 0x37, 0xb4, 0x35, 0x8b, 0xe3, 0x71, 0x53, 0xc0, 0x3e, 0x84, 0xe1, 0x6b, 0x77, 0x16, 0x58, 0xde,
0xcd, 0xbe, 0xb9, 0x01, 0x83, 0x54, 0x53, 0x99, 0x36, 0x7f, 0xad, 0xc0, 0xe6, 0x63, 0xc7, 0x39, 0x32, 0x6e, 0x04, 0x5c, 0x20, 0x09, 0x4b, 0x81, 0x34, 0x34, 0x37, 0x60, 0x94, 0x7b, 0x4a, 0x1e,
0x8e, 0x02, 0x9b, 0xc5, 0xf1, 0x22, 0xc0, 0x0d, 0x68, 0x73, 0x16, 0xcd, 0x5c, 0x81, 0x22, 0x50, 0xe6, 0x2f, 0x35, 0xd8, 0x7c, 0xec, 0x38, 0x87, 0x71, 0x68, 0xb3, 0x24, 0x59, 0x06, 0xb8, 0x01,
0xdb, 0xc6, 0x1e, 0xd4, 0x93, 0x98, 0x29, 0x36, 0xdd, 0xc3, 0xee, 0x81, 0x8c, 0xd6, 0xc1, 0x29, 0x5d, 0xce, 0x62, 0xdf, 0xcd, 0x50, 0x32, 0xd4, 0xae, 0xb1, 0x0b, 0xcd, 0x34, 0x61, 0xb1, 0xc0,
0x6e, 0x19, 0x3d, 0xa8, 0x5b, 0xd1, 0x24, 0x1e, 0xd6, 0xf7, 0x6b, 0x8a, 0x0b, 0xf3, 0x2f, 0x86, 0xec, 0xef, 0xf7, 0xf7, 0x84, 0x74, 0x7b, 0xc7, 0xb8, 0x65, 0x0c, 0xa0, 0x69, 0xc5, 0xb3, 0x04,
0x8d, 0x74, 0x61, 0x5f, 0x3a, 0xc3, 0xa6, 0x04, 0xd5, 0x1e, 0xb7, 0x4a, 0x1e, 0xb7, 0x4b, 0x1e, 0x89, 0x36, 0x24, 0x17, 0x16, 0x9c, 0x8d, 0x5b, 0xf9, 0xc2, 0x3e, 0x77, 0xc6, 0x6d, 0x9d, 0x65,
0x77, 0xe4, 0x7a, 0x1d, 0x5a, 0x36, 0xd2, 0x0d, 0x3c, 0x36, 0x04, 0x0a, 0x41, 0x5d, 0xda, 0x43, 0x87, 0xf2, 0x69, 0x0a, 0x67, 0xdc, 0x4c, 0x95, 0x26, 0xb8, 0x98, 0x51, 0x1e, 0x43, 0x63, 0x07,
0xd0, 0x84, 0x98, 0xf6, 0xc5, 0x62, 0x42, 0xae, 0xf7, 0x8d, 0x5d, 0x18, 0x58, 0x8e, 0xe3, 0x72, 0x46, 0x96, 0xe3, 0xb8, 0xdc, 0x0d, 0x91, 0xc5, 0x33, 0xd7, 0x49, 0x30, 0x76, 0x03, 0xf3, 0x39,
0x37, 0x40, 0xe2, 0xcf, 0x5c, 0x27, 0x46, 0xba, 0x35, 0x0c, 0xc1, 0x36, 0x18, 0x79, 0x7f, 0x29, 0x00, 0x43, 0x27, 0x4f, 0xda, 0x2a, 0x39, 0x6b, 0x15, 0x39, 0xeb, 0x15, 0x39, 0x85, 0xbc, 0x58,
0x0c, 0x2f, 0x74, 0x72, 0x74, 0xda, 0x16, 0xc5, 0xe2, 0xdd, 0x42, 0x5e, 0xab, 0xd2, 0xff, 0x4d, 0xf3, 0xbc, 0x4a, 0xaa, 0x7e, 0xcb, 0x74, 0x78, 0xb7, 0x54, 0xe0, 0xba, 0xc8, 0x7d, 0x93, 0x72,
0xf2, 0x3f, 0xd3, 0x34, 0x47, 0x30, 0x9c, 0x47, 0x23, 0x4b, 0x0f, 0xe0, 0xc6, 0x13, 0xe6, 0xb1, 0x2f, 0x3c, 0xcd, 0x09, 0x8c, 0x17, 0xd1, 0x48, 0xec, 0x07, 0x70, 0xfd, 0x09, 0xf3, 0xd8, 0x9b,
0x37, 0x59, 0xc2, 0x40, 0xfa, 0xd6, 0x8c, 0xa9, 0x3c, 0x0a, 0xc0, 0x79, 0x25, 0x02, 0x7c, 0x07, 0x22, 0xa1, 0x88, 0x81, 0xe5, 0x33, 0x49, 0x37, 0x03, 0x5c, 0x74, 0x22, 0xc0, 0x77, 0x60, 0xfb,
0x76, 0x5e, 0xb8, 0x31, 0x5f, 0x09, 0x67, 0x7e, 0x0f, 0x90, 0x09, 0x68, 0x70, 0x6d, 0x8a, 0x5d, 0x85, 0x9b, 0xf0, 0x2b, 0xe1, 0xcc, 0xef, 0x01, 0x0a, 0x03, 0x05, 0xae, 0x42, 0xb1, 0x0b, 0x97,
0xb9, 0x9c, 0x92, 0x8b, 0x41, 0xe4, 0x76, 0x28, 0x73, 0xdb, 0x36, 0xb6, 0xa0, 0x9b, 0xf8, 0xee, 0x53, 0x61, 0x51, 0x73, 0x6e, 0x47, 0x42, 0x96, 0xae, 0xb1, 0x05, 0xfd, 0x34, 0x70, 0x2f, 0x5e,
0xd5, 0xeb, 0xc0, 0x9e, 0x32, 0x2e, 0xb2, 0x2a, 0x36, 0x45, 0xee, 0xce, 0x99, 0xe7, 0x61, 0x5e, 0x87, 0xf6, 0x9c, 0xf1, 0x44, 0xb4, 0x5e, 0x57, 0x48, 0x7b, 0xca, 0x3c, 0x0f, 0x6b, 0x8a, 0x4b,
0x71, 0x69, 0x7e, 0x01, 0xbb, 0x65, 0xfb, 0x54, 0xd6, 0xef, 0x41, 0x37, 0x8b, 0x56, 0x8c, 0xd6, 0xf3, 0x0b, 0xd8, 0xa9, 0xc6, 0xa7, 0x1a, 0xbc, 0x07, 0xfd, 0x42, 0xad, 0x04, 0xa3, 0x35, 0x96,
0x6a, 0x8b, 0xc3, 0x35, 0x80, 0xde, 0x6b, 0x8e, 0xd1, 0x22, 0xe2, 0xe6, 0x3e, 0x0c, 0x74, 0x8f, 0xcb, 0x35, 0x82, 0xc1, 0x6b, 0x8e, 0x6a, 0x11, 0x71, 0xf3, 0x16, 0x8c, 0xd4, 0xb0, 0x88, 0x0f,
0xc8, 0x03, 0x55, 0x0f, 0x16, 0x4f, 0x62, 0x72, 0x67, 0x0a, 0x2d, 0xca, 0x60, 0x5a, 0xef, 0xff, 0xb2, 0x5c, 0x16, 0x4f, 0x13, 0x4a, 0x67, 0x0e, 0x1d, 0x2a, 0xb8, 0x3e, 0x44, 0xff, 0x4d, 0x9f,
0x5d, 0xad, 0x9a, 0x1e, 0x74, 0x34, 0x9d, 0xe5, 0x39, 0x2a, 0xcd, 0x01, 0xd9, 0xa9, 0xc6, 0xdb, 0x9a, 0x1e, 0xf4, 0x14, 0x9d, 0xd5, 0x35, 0xaa, 0x1c, 0x08, 0x72, 0x6a, 0xdf, 0x86, 0x5e, 0x24,
0xd0, 0x09, 0x15, 0x4f, 0xa6, 0xec, 0x74, 0x0f, 0x07, 0x44, 0x21, 0xe5, 0x9f, 0xb9, 0xd6, 0x90, 0x79, 0x32, 0x19, 0xa7, 0xbf, 0x3f, 0x22, 0x0a, 0x39, 0xff, 0x22, 0xb5, 0x96, 0x88, 0x76, 0x07,
0xd6, 0xee, 0x40, 0xeb, 0xa5, 0x65, 0x9f, 0xa3, 0x31, 0x81, 0x6f, 0x87, 0xe4, 0x73, 0x5f, 0x08, 0x3a, 0x2f, 0x2d, 0xfb, 0x14, 0x83, 0x65, 0xf8, 0x76, 0x44, 0x39, 0x0f, 0x33, 0x43, 0x9f, 0xf9,
0xce, 0xd8, 0x2c, 0x88, 0xae, 0xa5, 0xbd, 0xba, 0xf9, 0x1d, 0x4e, 0x01, 0x15, 0x35, 0x0a, 0xf7, 0x61, 0x7c, 0x29, 0xe2, 0x35, 0xcd, 0xef, 0xf0, 0x04, 0x90, 0xaa, 0x91, 0xdc, 0xb7, 0xb1, 0x39,
0x6d, 0x2c, 0xce, 0x94, 0x67, 0x1a, 0xed, 0x8d, 0x34, 0xda, 0xda, 0x81, 0x5b, 0xd0, 0x9a, 0x29, 0x73, 0x9e, 0xb9, 0xda, 0x1b, 0xb9, 0xda, 0x2a, 0x81, 0x9b, 0xd0, 0xf1, 0x25, 0x3e, 0xf5, 0x6f,
0x7c, 0xaa, 0xdf, 0x94, 0x10, 0x59, 0x35, 0x9f, 0xc0, 0xee, 0x69, 0xe8, 0xbc, 0x69, 0xea, 0x65, 0x4e, 0x88, 0xa2, 0x9a, 0x4f, 0x60, 0xe7, 0x38, 0x72, 0xde, 0x74, 0xfc, 0x15, 0xa7, 0x4a, 0x3d,
0x93, 0xa5, 0x9a, 0xb2, 0x23, 0x37, 0xd4, 0x8c, 0xda, 0x83, 0x1b, 0x73, 0x28, 0x54, 0xb0, 0xeb, 0x67, 0x47, 0x69, 0xc8, 0x81, 0xda, 0x85, 0xeb, 0x0b, 0x28, 0xd4, 0xb0, 0xeb, 0x30, 0x7c, 0x7a,
0xd0, 0x7f, 0x7a, 0xc1, 0xb0, 0x22, 0xd2, 0x7c, 0xff, 0x59, 0x81, 0x86, 0xdc, 0x11, 0x1e, 0x0b, 0xc6, 0xb0, 0x23, 0xf2, 0x7a, 0xff, 0x59, 0x83, 0x96, 0xd8, 0xc9, 0x32, 0xce, 0xc8, 0x50, 0x0c,
0x32, 0x64, 0x43, 0xd9, 0xcb, 0xcd, 0x40, 0x8d, 0xdf, 0x2f, 0x45, 0xbb, 0x9e, 0x1f, 0x7d, 0x8d, 0x19, 0x4f, 0x1b, 0x58, 0x85, 0x3f, 0xac, 0xa8, 0xdd, 0xd4, 0x0f, 0x94, 0x56, 0x85, 0x60, 0x47,
0x12, 0xc1, 0x96, 0x54, 0x40, 0xbf, 0x29, 0x15, 0x72, 0xc6, 0xcc, 0x27, 0xa2, 0x18, 0xbe, 0xce, 0x38, 0x60, 0xde, 0x54, 0x8a, 0x71, 0xb7, 0x94, 0x77, 0x5e, 0x88, 0xb2, 0x7c, 0xbd, 0x15, 0xf2,
0x92, 0xf0, 0x15, 0x27, 0x00, 0x2c, 0x9b, 0x00, 0xbf, 0x55, 0xa0, 0xf7, 0x0d, 0xe3, 0x97, 0x41, 0x95, 0x4f, 0x00, 0x58, 0x75, 0x02, 0xfc, 0x56, 0x83, 0xc1, 0x37, 0x8c, 0x9f, 0x87, 0xf1, 0x3c,
0x34, 0x15, 0x49, 0x8a, 0x4b, 0x2d, 0x87, 0x75, 0x1a, 0x5d, 0x8d, 0xcf, 0xae, 0x39, 0x96, 0x85, 0x2b, 0x52, 0x52, 0x19, 0x39, 0xec, 0xd3, 0xf8, 0x62, 0x7a, 0x72, 0xc9, 0xb1, 0x2d, 0x44, 0x35,
0xcc, 0xa6, 0xf0, 0x07, 0x77, 0x8e, 0x2d, 0xd5, 0x68, 0x35, 0xb9, 0xb7, 0x09, 0x9d, 0x57, 0x57, 0xb3, 0x7c, 0x70, 0xe7, 0xd0, 0x92, 0x83, 0xd6, 0x10, 0x7b, 0x9b, 0xd0, 0x7b, 0x75, 0x31, 0xc5,
0x63, 0x9c, 0x82, 0x41, 0xa4, 0x7a, 0x4f, 0x8a, 0xe1, 0x96, 0x13, 0x05, 0x61, 0xc8, 0x94, 0xa7, 0x43, 0x2a, 0x8c, 0xe5, 0xec, 0x09, 0x33, 0xdc, 0x72, 0xe2, 0x30, 0x8a, 0x98, 0xcc, 0xb4, 0x99,
0x75, 0x01, 0x76, 0x92, 0x82, 0x35, 0x53, 0x29, 0xdc, 0x09, 0x09, 0xac, 0x95, 0x82, 0x9d, 0x68, 0x81, 0x1d, 0xe5, 0x60, 0xed, 0xdc, 0x0a, 0x77, 0x22, 0x02, 0xeb, 0xe4, 0x60, 0x47, 0x0a, 0xac,
0xb0, 0x76, 0x4e, 0x2c, 0x05, 0xeb, 0xc8, 0xaa, 0x9a, 0x41, 0xfb, 0x28, 0x4c, 0x4e, 0x63, 0x6b, 0xab, 0x99, 0xe5, 0x60, 0x3d, 0xd1, 0x55, 0x3e, 0x74, 0x0f, 0xa2, 0xf4, 0x38, 0xb1, 0x66, 0x2c,
0xc2, 0x44, 0xf7, 0xf3, 0x80, 0x5b, 0xde, 0x38, 0x11, 0x4b, 0x49, 0xbd, 0x6e, 0x6c, 0x43, 0x2f, 0x9b, 0x7e, 0x1e, 0x72, 0xcb, 0x9b, 0xa6, 0xd9, 0x52, 0x50, 0x6f, 0x1a, 0xd7, 0x60, 0x10, 0xb1,
0x64, 0x11, 0xd6, 0x25, 0xed, 0x56, 0x31, 0x50, 0x75, 0xe3, 0x7f, 0xb0, 0x25, 0x97, 0x63, 0xd7, 0x18, 0xfb, 0x92, 0x76, 0xeb, 0x28, 0x54, 0xd3, 0xf8, 0x1f, 0x6c, 0x89, 0xe5, 0xd4, 0x0d, 0xa6,
0x1f, 0x4f, 0x59, 0xe4, 0x33, 0x6f, 0x16, 0x38, 0x8c, 0xfc, 0xd8, 0x83, 0x4d, 0x7d, 0x28, 0x9a, 0x73, 0x16, 0x07, 0xcc, 0xf3, 0x43, 0x87, 0x51, 0x1e, 0xbb, 0xb0, 0xa9, 0x3e, 0x66, 0xc3, 0x28,
0x51, 0x1e, 0x49, 0x7f, 0xcc, 0x13, 0x18, 0x9c, 0x9c, 0xe3, 0x37, 0x97, 0x7b, 0xae, 0x3f, 0x79, 0x3e, 0x89, 0x7c, 0xcc, 0x23, 0x18, 0x1d, 0x9d, 0xe2, 0x8f, 0x2f, 0xf7, 0xdc, 0x60, 0xf6, 0xc4,
0x62, 0x71, 0x4b, 0x8c, 0x7a, 0xc4, 0x77, 0x03, 0x27, 0x26, 0x83, 0xa8, 0xcd, 0x95, 0x08, 0x73, 0xe2, 0x96, 0xb1, 0x8e, 0x75, 0x62, 0xb1, 0x1b, 0x3a, 0x09, 0x05, 0x44, 0x6f, 0x2e, 0x4d, 0x98,
0xc6, 0xe9, 0x91, 0x0a, 0x1a, 0xce, 0xf8, 0xec, 0x88, 0xbb, 0x33, 0x32, 0x68, 0xfe, 0x20, 0x9d, 0x33, 0xcd, 0x3f, 0x49, 0xd1, 0xf0, 0x27, 0xa1, 0xf8, 0xc4, 0x5d, 0x9f, 0x02, 0x9a, 0x3f, 0x88,
0x50, 0x81, 0x37, 0xa1, 0x93, 0x91, 0xad, 0xc8, 0x7c, 0xad, 0xa7, 0xf9, 0x4a, 0x1d, 0x3d, 0x80, 0x24, 0xa4, 0xf0, 0x26, 0xf4, 0x0a, 0xb2, 0x35, 0x51, 0xaf, 0xf5, 0xbc, 0x5e, 0x79, 0xa2, 0x7b,
0x75, 0xae, 0x59, 0x8c, 0xb1, 0x6a, 0x2d, 0xea, 0x8d, 0x1d, 0x92, 0x2c, 0x72, 0x34, 0x3f, 0x07, 0xb0, 0xce, 0x15, 0x8b, 0x29, 0x76, 0xad, 0x45, 0xb3, 0xb1, 0x4d, 0x96, 0x65, 0x8e, 0xe6, 0xe7,
0x78, 0x29, 0x5b, 0x51, 0x32, 0xc6, 0x79, 0x98, 0x0f, 0x10, 0x06, 0x7a, 0x66, 0x5d, 0xe9, 0xe8, 0x00, 0x2f, 0xc5, 0x28, 0x0a, 0xc6, 0x78, 0x1e, 0xea, 0x02, 0xa1, 0xd0, 0xbe, 0x75, 0xa1, 0xd4,
0x88, 0x2d, 0xf4, 0xe9, 0x47, 0xcb, 0xf5, 0x6c, 0xba, 0x0b, 0xd4, 0xcd, 0xbf, 0x2a, 0xd0, 0x55, 0xc9, 0xb6, 0x30, 0xa7, 0x1f, 0x2d, 0xd7, 0xb3, 0x03, 0x4e, 0x04, 0xff, 0xaa, 0x41, 0x5f, 0x22,
0x08, 0x8a, 0x24, 0x42, 0xd8, 0xd8, 0x7e, 0x29, 0xc4, 0x7e, 0x8a, 0x58, 0xfc, 0xc2, 0xe4, 0x6c, 0x48, 0x92, 0x08, 0x61, 0xe3, 0xf8, 0xe5, 0x10, 0xb7, 0x72, 0xc4, 0xf2, 0x2f, 0x8c, 0x16, 0x13,
0x62, 0x19, 0xc6, 0x97, 0x56, 0x48, 0x56, 0x6a, 0xcb, 0xc4, 0xee, 0x40, 0x4f, 0x65, 0x83, 0x04, 0xdb, 0x30, 0x39, 0xb7, 0x22, 0x8a, 0xd2, 0x58, 0x65, 0x76, 0x07, 0x06, 0xb2, 0x1a, 0x64, 0xd8,
0xeb, 0xcb, 0x04, 0xef, 0x89, 0xef, 0x31, 0x32, 0x91, 0xf3, 0xaf, 0x7b, 0x78, 0xb3, 0x20, 0x21, 0x5c, 0x65, 0x78, 0x2f, 0xfb, 0xb9, 0x44, 0x26, 0xe2, 0xfc, 0xeb, 0xef, 0xdf, 0x28, 0x59, 0x08,
0x39, 0x1e, 0xc8, 0xdf, 0xa7, 0x3e, 0x8f, 0xae, 0x47, 0xf7, 0x00, 0xb2, 0x95, 0x68, 0xbb, 0x29, 0x8e, 0x7b, 0xe2, 0xef, 0xd3, 0x80, 0xc7, 0x97, 0x93, 0x7b, 0x00, 0xc5, 0x2a, 0x1b, 0xbb, 0x39,
0xbb, 0xa6, 0xca, 0x46, 0x4f, 0x2e, 0x2c, 0x2f, 0x21, 0xcf, 0x1f, 0x55, 0x1f, 0x56, 0xcc, 0xaf, 0xbb, 0xa4, 0xce, 0xc6, 0x4c, 0xce, 0x2c, 0x2f, 0xa5, 0xcc, 0x1f, 0xd5, 0x1f, 0xd6, 0xcc, 0xaf,
0x61, 0xfd, 0x4b, 0x6f, 0xea, 0x06, 0x39, 0x15, 0x94, 0x9a, 0x59, 0x3f, 0x05, 0x11, 0xf9, 0x2b, 0x61, 0xfd, 0x4b, 0x6f, 0xee, 0x86, 0x9a, 0x0b, 0x5a, 0xf9, 0xd6, 0x4f, 0x61, 0x4c, 0xf9, 0x66,
0x96, 0xae, 0x8f, 0x4b, 0x15, 0x2e, 0xec, 0xfb, 0x20, 0xa4, 0x09, 0xaa, 0xf1, 0x54, 0xbd, 0xfc, 0x4b, 0x37, 0xc0, 0xa5, 0x94, 0x0b, 0xe7, 0x3e, 0x8c, 0xe8, 0x04, 0x55, 0x78, 0xb2, 0x5f, 0x7e,
0x5e, 0x03, 0xc8, 0xc0, 0x8c, 0x47, 0x30, 0x72, 0x83, 0x31, 0x96, 0xd4, 0x85, 0x6b, 0x33, 0xd5, 0x6f, 0x00, 0x14, 0x60, 0xc6, 0x23, 0x98, 0xb8, 0xe1, 0x14, 0x5b, 0xea, 0xcc, 0xb5, 0x99, 0x1c,
0x02, 0xe3, 0x88, 0xd9, 0x49, 0x14, 0xbb, 0x17, 0x8c, 0x46, 0xe0, 0x2e, 0xf9, 0x52, 0xe6, 0xf0, 0x81, 0x69, 0xcc, 0xec, 0x34, 0x4e, 0xdc, 0x33, 0x46, 0x47, 0xe0, 0x0e, 0xe5, 0x52, 0xe5, 0xf0,
0x11, 0xec, 0x64, 0xba, 0x4e, 0x4e, 0xad, 0xba, 0x52, 0xed, 0x01, 0x6c, 0xa1, 0x1a, 0x0e, 0xae, 0x11, 0x6c, 0x17, 0xbe, 0x8e, 0xe6, 0x56, 0xbf, 0xd2, 0xed, 0x01, 0x6c, 0xa1, 0x1b, 0x1e, 0x5c,
0xa4, 0xa0, 0x54, 0x5b, 0xa9, 0xf4, 0x29, 0xec, 0xe5, 0x78, 0x8a, 0x4a, 0xcd, 0xa9, 0xd6, 0x57, 0x69, 0xc9, 0xa9, 0x71, 0xa5, 0xd3, 0xa7, 0xb0, 0xab, 0xf1, 0xcc, 0x3a, 0x55, 0x73, 0x6d, 0x5e,
0xaa, 0x7e, 0x0c, 0xbb, 0xa8, 0x7a, 0x69, 0xb9, 0xbc, 0xac, 0xd7, 0xf8, 0x07, 0x3c, 0x67, 0x2c, 0xe9, 0xfa, 0x31, 0xec, 0xa0, 0xeb, 0xb9, 0xe5, 0xf2, 0xaa, 0x5f, 0xeb, 0x1f, 0xf0, 0xf4, 0x59,
0x9a, 0x14, 0x78, 0x36, 0x57, 0x2a, 0x7d, 0x00, 0x9b, 0xa8, 0x54, 0xb2, 0xd3, 0x7a, 0x93, 0x4a, 0x3c, 0x2b, 0xf1, 0x6c, 0x5f, 0xe9, 0xf4, 0x01, 0x6c, 0xa2, 0x53, 0x25, 0x4e, 0xe7, 0x4d, 0x2e,
0xcc, 0x6c, 0x8e, 0x53, 0x25, 0xa7, 0xd2, 0x5e, 0xa5, 0x62, 0x3e, 0x86, 0xde, 0xf3, 0x64, 0xc2, 0x09, 0xb3, 0x39, 0x9e, 0x2a, 0x9a, 0x4b, 0xf7, 0x2a, 0x17, 0xf3, 0x31, 0x0c, 0x9e, 0xa7, 0x33,
0xb8, 0x77, 0xa6, 0xab, 0xff, 0xdf, 0x36, 0xd0, 0x2f, 0x55, 0xe8, 0x1e, 0x4d, 0xa2, 0x20, 0x09, 0xc6, 0xbd, 0x13, 0xd5, 0xfd, 0xff, 0x76, 0x80, 0x7e, 0xad, 0x43, 0xff, 0x60, 0x16, 0x87, 0x69,
0x0b, 0x5d, 0xae, 0x6a, 0x78, 0xae, 0xcb, 0x95, 0xcc, 0x5d, 0xe8, 0xa9, 0x0f, 0x28, 0x89, 0xa9, 0x54, 0x9a, 0x72, 0xd9, 0xc3, 0x0b, 0x53, 0x2e, 0x6d, 0xee, 0xc2, 0x40, 0xfe, 0x80, 0x92, 0x99,
0xe6, 0x32, 0xe6, 0x4b, 0x5d, 0x5c, 0x5c, 0xce, 0x04, 0x67, 0x12, 0x2c, 0xb6, 0x57, 0xae, 0xfc, 0x1c, 0x2e, 0x63, 0xb1, 0xd5, 0xb3, 0x8b, 0xcb, 0x49, 0xc6, 0x99, 0x0c, 0xcb, 0xe3, 0xa5, 0xb5,
0x3e, 0x83, 0xfe, 0xb9, 0x72, 0x84, 0x24, 0x55, 0x2a, 0x6f, 0xa7, 0x96, 0x33, 0x82, 0x07, 0x79, 0xdf, 0x67, 0x30, 0x3c, 0x95, 0x89, 0x90, 0xa5, 0x2c, 0xe5, 0xed, 0x3c, 0x72, 0x41, 0x70, 0x4f,
0x87, 0x55, 0x13, 0x3d, 0x87, 0xcd, 0xb9, 0xcd, 0x62, 0x2f, 0x99, 0xf9, 0x5e, 0xea, 0x1e, 0x6e, 0x4f, 0x58, 0x0e, 0xd1, 0x73, 0xd8, 0x5c, 0xd8, 0x2c, 0xcf, 0x92, 0xa9, 0xcf, 0x52, 0x7f, 0x7f,
0x11, 0x6c, 0x5e, 0x4b, 0x36, 0x58, 0x08, 0x0d, 0xc5, 0xe7, 0x7d, 0xe8, 0xfb, 0xea, 0xa3, 0xa3, 0x8b, 0x60, 0x75, 0x2f, 0x31, 0x60, 0x11, 0xb4, 0x24, 0x9f, 0xf7, 0x61, 0x18, 0xc8, 0x1f, 0x1d,
0x23, 0x51, 0xcb, 0x29, 0x16, 0x3e, 0x48, 0x18, 0x0d, 0x5b, 0xf2, 0x5b, 0x18, 0x8d, 0x7c, 0x6c, 0xa5, 0x44, 0x43, 0x73, 0x2c, 0xfd, 0x20, 0xa1, 0x1a, 0xb6, 0xe0, 0xb7, 0x54, 0x0d, 0x5d, 0x5b,
0x31, 0x1f, 0xa2, 0x22, 0x50, 0x6c, 0x16, 0x52, 0xf8, 0x47, 0xea, 0xc6, 0xb6, 0xe8, 0xbd, 0x70, 0xac, 0x47, 0xd6, 0x11, 0x68, 0xe6, 0x47, 0x24, 0xff, 0x44, 0xde, 0xd8, 0x96, 0xbd, 0x15, 0xf6,
0xf8, 0x47, 0x03, 0x6a, 0x8f, 0x8f, 0xbf, 0x32, 0x5e, 0xc1, 0x7a, 0xe9, 0xbd, 0x63, 0xa4, 0x63, 0xff, 0x68, 0x41, 0xe3, 0xf1, 0xe1, 0x57, 0xc6, 0x2b, 0x58, 0xaf, 0x3c, 0x7c, 0x8c, 0xfc, 0x58,
0x65, 0xf1, 0xab, 0x6a, 0xf4, 0xd6, 0xb2, 0x63, 0xba, 0x38, 0xac, 0x09, 0xcc, 0xd2, 0xad, 0x42, 0x59, 0xfe, 0xbc, 0x9a, 0xbc, 0xb5, 0xea, 0x33, 0x5d, 0x1c, 0xd6, 0x32, 0xcc, 0xca, 0xad, 0x42,
0x63, 0x2e, 0xbe, 0xb3, 0x68, 0xcc, 0x65, 0x97, 0x91, 0x35, 0xe3, 0x13, 0x68, 0xaa, 0x37, 0x91, 0x61, 0x2e, 0xbf, 0xb3, 0x28, 0xcc, 0x55, 0x97, 0x91, 0x35, 0xe3, 0x13, 0x68, 0xcb, 0xf7, 0x90,
0xb1, 0x4d, 0xb2, 0x85, 0xc7, 0xd5, 0x68, 0xa7, 0xb4, 0xab, 0x15, 0x8f, 0x00, 0xb2, 0x97, 0x84, 0x71, 0x8d, 0x6c, 0x4b, 0x0f, 0xab, 0xc9, 0x76, 0x65, 0x57, 0x39, 0x1e, 0x00, 0x14, 0x0f, 0x0f,
0x31, 0x24, 0xb1, 0xb9, 0xc7, 0xd4, 0x68, 0x6f, 0xc1, 0x89, 0x06, 0x39, 0x85, 0x8d, 0xf2, 0x53, 0x63, 0x4c, 0x66, 0x0b, 0x0f, 0xa9, 0xc9, 0xee, 0x92, 0x2f, 0x0a, 0xe4, 0x18, 0x36, 0xaa, 0x4f,
0xc1, 0x28, 0xc5, 0xa1, 0x7c, 0xb1, 0x1f, 0xdd, 0x5a, 0x7a, 0x9e, 0x87, 0x2d, 0x3f, 0x18, 0x34, 0x05, 0xa3, 0xa2, 0x43, 0xf5, 0x62, 0x3f, 0xb9, 0xb9, 0xf2, 0xbb, 0x0e, 0x5b, 0x7d, 0x30, 0x28,
0xec, 0x92, 0xe7, 0x87, 0x86, 0x5d, 0xfa, 0xd2, 0x58, 0x33, 0xbe, 0x85, 0x41, 0xf1, 0xae, 0x6f, 0xd8, 0x15, 0xcf, 0x0f, 0x05, 0xbb, 0xf2, 0xa5, 0xb1, 0x66, 0x7c, 0x0b, 0xa3, 0xf2, 0x5d, 0xdf,
0xfc, 0x9f, 0x94, 0x16, 0x3e, 0x41, 0x46, 0x37, 0x97, 0x9c, 0x6a, 0xc0, 0x0f, 0x55, 0xe9, 0xe2, 0xf8, 0x3f, 0x39, 0x2d, 0x7d, 0x82, 0x4c, 0x6e, 0xac, 0xf8, 0xaa, 0x00, 0x3f, 0x94, 0xad, 0x8b,
0x5d, 0x23, 0x8d, 0x72, 0xee, 0x21, 0x30, 0xda, 0x2e, 0x6e, 0x6a, 0xad, 0xfb, 0xd0, 0x54, 0x37, 0x77, 0x8d, 0x5c, 0x65, 0xed, 0x21, 0x30, 0xb9, 0x56, 0xde, 0x54, 0x5e, 0xf7, 0xa1, 0x2d, 0x6f,
0x48, 0x9d, 0xb2, 0xc2, 0x85, 0x72, 0xd4, 0xcb, 0xef, 0x9a, 0x6b, 0xf7, 0x2b, 0x38, 0xa5, 0xda, 0x90, 0xaa, 0x64, 0xa5, 0x0b, 0xe5, 0x64, 0xa0, 0xef, 0x9a, 0x6b, 0xf7, 0x6b, 0x78, 0x4a, 0x75,
0xcf, 0x18, 0x57, 0xf5, 0x9c, 0x37, 0x35, 0xa7, 0x22, 0x37, 0x85, 0xca, 0x59, 0x53, 0xfe, 0x17, 0x9f, 0x31, 0x2e, 0xfb, 0x59, 0x0f, 0xb5, 0xe0, 0x22, 0x36, 0x33, 0x97, 0x93, 0xb6, 0xf8, 0xa7,
0xf0, 0xe0, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x15, 0x52, 0xba, 0x18, 0x10, 0x00, 0x00, 0xc0, 0x83, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x0f, 0x82, 0xdf, 0x21, 0x10, 0x00, 0x00,
} }

View file

@ -23,9 +23,9 @@ message CreateContainerRequest {
message CreateContainerResponse { message CreateContainerResponse {
uint32 pid = 1; // PID of the containers main process uint32 pid = 1; // PID of the containers main process
string stdin = 1; // path to the file where stdin will be read (optional) string stdin = 2; // path to the file where stdin will be read (optional)
string stdout = 2; // path to file where stdout will be written (optional) string stdout = 3; // path to file where stdout will be written (optional)
string stderr = 3; // path to file where stderr will be written (optional) string stderr = 4; // path to file where stderr will be written (optional)
} }
message SignalRequest { message SignalRequest {
@ -44,10 +44,7 @@ message AddProcessRequest {
repeated string args = 4; // Arguments for process, first is binary path itself repeated string args = 4; // Arguments for process, first is binary path itself
repeated string env = 5; // List of environment variables for process repeated string env = 5; // List of environment variables for process
string cwd = 6; // Workind directory of process string cwd = 6; // Workind directory of process
string stdin = 7; // path to the file where stdin will be read (optional) string pid = 7; // Process ID
string stdout = 8; // path to file where stdout will be written (optional)
string stderr = 9; // path to file where stderr will be written (optional)
string console = 10; // path to the console for a container (optional)
}; };
message User { message User {
@ -57,6 +54,9 @@ message User {
} }
message AddProcessResponse { message AddProcessResponse {
string stdin = 1; // path to the file where stdin will be read (optional)
string stdout = 2; // path to file where stdout will be written (optional)
string stderr = 3; // path to file where stderr will be written (optional)
} }
message CreateCheckpointRequest { message CreateCheckpointRequest {

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

View file

@ -1,43 +1,21 @@
package main package main
import ( import (
"encoding/json" "flag"
"fmt" "fmt"
"io"
"io/ioutil"
"os" "os"
"os/exec"
"os/signal" "os/signal"
"path/filepath"
"strconv"
"syscall" "syscall"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/containerd/util" "github.com/docker/containerd/util"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/specs"
) )
const ( var fexec bool
bufferSize = 2048
)
type stdio struct { func init() {
stdin *os.File flag.BoolVar(&fexec, "exec", false, "exec a process instead of starting the init")
stdout *os.File flag.Parse()
stderr *os.File
console string
}
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
} }
// containerd-shim is a small shim that sits in front of a runc implementation // containerd-shim is a small shim that sits in front of a runc implementation
@ -45,41 +23,27 @@ func (s *stdio) Close() error {
// //
// the cwd of the shim should be the bundle for the container. Arg1 should be the path // the cwd of the shim should be the bundle for the container. Arg1 should be the path
// to the state directory where the shim can locate fifos and other information. // to the state directory where the shim can locate fifos and other information.
//
// └── shim
// ├── control
// ├── stderr
// ├── stdin
// ├── stdout
// ├── pid
// └── exit
func main() { func main() {
if len(os.Args) < 2 {
logrus.Fatal("shim: no arguments provided")
}
// start handling signals as soon as possible so that things are properly reaped // start handling signals as soon as possible so that things are properly reaped
// or if runc exits before we hit the handler // or if runc exits before we hit the handler
signals := make(chan os.Signal, bufferSize) signals := make(chan os.Signal, 2048)
signal.Notify(signals) signal.Notify(signals)
// set the shim as the subreaper for all orphaned processes created by the container // set the shim as the subreaper for all orphaned processes created by the container
if err := util.SetSubreaper(1); err != nil { if err := util.SetSubreaper(1); err != nil {
logrus.WithField("error", err).Fatal("shim: set as subreaper") logrus.WithField("error", err).Fatal("shim: set as subreaper")
} }
// open the exit pipe // open the exit pipe
f, err := os.OpenFile(filepath.Join(os.Args[1], "exit"), syscall.O_WRONLY, 0) f, err := os.OpenFile("exit", syscall.O_WRONLY, 0)
if err != nil { if err != nil {
logrus.WithField("error", err).Fatal("shim: open exit pipe") logrus.WithField("error", err).Fatal("shim: open exit pipe")
} }
defer f.Close() defer f.Close()
// open the fifos for use with the command p, err := newProcess(flag.Arg(0), flag.Arg(1), fexec)
std, err := openContainerSTDIO(os.Args[1])
if err != nil { if err != nil {
logrus.WithField("error", err).Fatal("shim: open container STDIO from fifo") logrus.WithField("error", err).Fatal("shim: create new process")
} }
// star the container process by invoking runc if err := p.start(); err != nil {
runcPid, err := startRunc(std, os.Args[2]) logrus.WithField("error", err).Fatal("shim: start process")
if err != nil {
logrus.WithField("error", err).Fatal("shim: start runc")
} }
var exitShim bool var exitShim bool
for s := range signals { for s := range signals {
@ -92,22 +56,27 @@ func main() {
} }
for _, e := range exits { for _, e := range exits {
// check to see if runc is one of the processes that has exited // check to see if runc is one of the processes that has exited
if e.Pid == runcPid { if e.Pid == p.pid() {
exitShim = true exitShim = true
logrus.WithFields(logrus.Fields{"pid": e.Pid, "status": e.Status}).Info("shim: runc exited") logrus.WithFields(logrus.Fields{
"pid": e.Pid,
if err := writeInt(filepath.Join(os.Args[1], "exitStatus"), e.Status); err != nil { "status": e.Status,
logrus.WithFields(logrus.Fields{"error": err, "status": e.Status}).Error("shim: write exit status") }).Info("shim: runc exited")
if err := writeInt("exitStatus", e.Status); err != nil {
logrus.WithFields(logrus.Fields{
"error": err,
"status": e.Status,
}).Error("shim: write exit status")
} }
} }
} }
} }
// runc has exited so the shim can also exit // runc has exited so the shim can also exit
if exitShim { if exitShim {
if err := std.Close(); err != nil { if err := p.Close(); err != nil {
logrus.WithField("error", err).Error("shim: close stdio") logrus.WithField("error", err).Error("shim: close stdio")
} }
if err := deleteContainer(os.Args[2]); err != nil { if err := p.delete(); err != nil {
logrus.WithField("error", err).Error("shim: delete runc state") logrus.WithField("error", err).Error("shim: delete runc state")
} }
return return
@ -115,90 +84,6 @@ func main() {
} }
} }
// startRunc starts runc detached and returns the container's pid
func startRunc(s *stdio, id string) (int, error) {
pidFile := filepath.Join(os.Args[1], "pid")
cmd := exec.Command("runc", "--id", id, "start", "-d", "--console", s.console, "--pid-file", pidFile)
cmd.Stdin = s.stdin
cmd.Stdout = s.stdout
cmd.Stderr = s.stderr
// set the parent death signal to SIGKILL so that if the shim dies the container
// process also dies
cmd.SysProcAttr = &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
}
if err := cmd.Run(); err != nil {
return -1, err
}
data, err := ioutil.ReadFile(pidFile)
if err != nil {
return -1, err
}
return strconv.Atoi(string(data))
}
func deleteContainer(id string) error {
return exec.Command("runc", "--id", id, "delete").Run()
}
// openContainerSTDIO 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 openContainerSTDIO(dir string) (*stdio, error) {
s := &stdio{}
spec, err := getSpec()
if err != nil {
return nil, err
}
if spec.Process.Terminal {
console, err := libcontainer.NewConsole(int(spec.Process.User.UID), int(spec.Process.User.GID))
if err != nil {
return nil, err
}
s.console = console.Path()
stdin, err := os.OpenFile(filepath.Join(dir, "stdin"), syscall.O_RDWR, 0)
if err != nil {
return nil, err
}
go func() {
io.Copy(console, stdin)
}()
stdout, err := os.OpenFile(filepath.Join(dir, "stdout"), syscall.O_RDWR, 0)
if err != nil {
return nil, err
}
go func() {
io.Copy(stdout, console)
console.Close()
}()
return s, nil
}
for name, dest := range map[string]**os.File{
"stdin": &s.stdin,
"stdout": &s.stdout,
"stderr": &s.stderr,
} {
f, err := os.OpenFile(filepath.Join(dir, name), syscall.O_RDWR, 0)
if err != nil {
return nil, err
}
*dest = f
}
return s, nil
}
func getSpec() (*specs.Spec, error) {
var s specs.Spec
f, err := os.Open("config.json")
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&s); err != nil {
return nil, err
}
return &s, nil
}
func writeInt(path string, i int) error { func writeInt(path string, i int) error {
f, err := os.Create(path) f, err := os.Create(path)
if err != nil { if err != nil {

165
containerd-shim/process.go Normal file
View file

@ -0,0 +1,165 @@
package main
import (
"encoding/json"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/specs"
)
type process struct {
id string
bundle string
stdio *stdio
s specs.Process
exec bool
containerPid int
}
func newProcess(id, bundle string, exec bool) (*process, error) {
f, err := os.Open("process.json")
if err != nil {
return nil, err
}
defer f.Close()
p := &process{
id: id,
bundle: bundle,
exec: exec,
}
if err := json.NewDecoder(f).Decode(&p.s); err != nil {
return nil, err
}
if err := p.openIO(); err != nil {
return nil, err
}
return p, nil
}
func (p *process) start() error {
cwd, err := os.Getwd()
if err != nil {
return err
}
args := []string{
"--id", p.id,
}
if p.exec {
args = append(args, "exec",
"--process", filepath.Join(cwd, "process.json"))
} else {
args = append(args, "start",
"--bundle", p.bundle)
}
args = append(args,
"-d",
"--console", p.stdio.console,
"--pid-file", filepath.Join(cwd, "pid"),
)
cmd := exec.Command("runc", args...)
cmd.Stdin = p.stdio.stdin
cmd.Stdout = p.stdio.stdout
cmd.Stderr = p.stdio.stderr
// set the parent death signal to SIGKILL so that if the shim dies the container
// process also dies
cmd.SysProcAttr = &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
}
if err := cmd.Run(); err != nil {
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 {
if !p.exec {
return exec.Command("runc", "--id", p.id, "delete").Run()
}
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 {
p.stdio = &stdio{}
if p.s.Terminal {
// FIXME: this is wrong for user namespaces and will need to be translated
console, err := libcontainer.NewConsole(int(p.s.User.UID), int(p.s.User.GID))
if err != nil {
return err
}
p.stdio.console = console.Path()
stdin, err := os.OpenFile("stdin", syscall.O_RDWR, 0)
if err != nil {
return err
}
go func() {
io.Copy(console, stdin)
}()
stdout, err := os.OpenFile("stdout", syscall.O_RDWR, 0)
if err != nil {
return err
}
go func() {
io.Copy(stdout, console)
console.Close()
}()
return nil
}
// non-tty
for name, dest := range map[string]**os.File{
"stdin": &p.stdio.stdin,
"stdout": &p.stdio.stdout,
"stderr": &p.stdio.stderr,
} {
f, err := os.OpenFile(name, syscall.O_RDWR, 0)
if err != nil {
return err
}
*dest = f
}
return nil
}
func (p *process) Close() error {
return p.stdio.Close()
}
type stdio struct {
stdin *os.File
stdout *os.File
stderr *os.File
console string
}
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
}

View file

@ -145,7 +145,7 @@ var attachCommand = cli.Command{
io.Copy(stdin, os.Stdin) io.Copy(stdin, os.Stdin)
closer() closer()
}() }()
if err := waitForExit(c, id, closer); err != nil { if err := waitForExit(c, id, "init", closer); err != nil {
fatal(err.Error(), 1) fatal(err.Error(), 1)
} }
}, },
@ -217,7 +217,7 @@ var startCommand = cli.Command{
io.Copy(stdin, os.Stdin) io.Copy(stdin, os.Stdin)
restoreAndCloseStdin() restoreAndCloseStdin()
}() }()
if err := waitForExit(c, id, restoreAndCloseStdin); err != nil { if err := waitForExit(c, id, "init", restoreAndCloseStdin); err != nil {
fatal(err.Error(), 1) fatal(err.Error(), 1)
} }
} }
@ -303,6 +303,10 @@ var execCommand = cli.Command{
Name: "id", Name: "id",
Usage: "container id to add the process to", Usage: "container id to add the process to",
}, },
cli.StringFlag{
Name: "pid",
Usage: "process id for the new process",
},
cli.BoolFlag{ cli.BoolFlag{
Name: "attach,a", Name: "attach,a",
Usage: "connect to the stdio of the container", Usage: "connect to the stdio of the container",
@ -330,58 +334,50 @@ var execCommand = cli.Command{
}, },
}, },
Action: func(context *cli.Context) { Action: func(context *cli.Context) {
panic("not implemented") p := &types.AddProcessRequest{
/* Pid: context.String("pid"),
p := &types.AddProcessRequest{ Args: context.Args(),
Args: context.Args(), Cwd: context.String("cwd"),
Cwd: context.String("cwd"), Terminal: context.Bool("tty"),
Terminal: context.Bool("tty"), Id: context.String("id"),
Id: context.String("id"), Env: context.StringSlice("env"),
Env: context.StringSlice("env"), User: &types.User{
User: &types.User{ Uid: uint32(context.Int("uid")),
Uid: uint32(context.Int("uid")), Gid: uint32(context.Int("gid")),
Gid: uint32(context.Int("gid")), },
}, }
} c := getClient(context)
c := getClient(context) resp, err := c.AddProcess(netcontext.Background(), p)
events, err := c.Events(netcontext.Background(), &types.EventsRequest{}) if err != nil {
if err != nil { fatal(err.Error(), 1)
fatal(err.Error(), 1) }
} if context.Bool("attach") {
if context.Bool("attach") { if context.Bool("tty") {
if p.Terminal { s, err := term.SetRawTerminal(os.Stdin.Fd())
if err := attachTty(&p.Console); err != nil {
fatal(err.Error(), 1)
}
} else {
if err := attachStdio(&p.Stdin, &p.Stdout, &p.Stderr); err != nil {
fatal(err.Error(), 1)
}
}
}
r, err := c.AddProcess(netcontext.Background(), p)
if err != nil { if err != nil {
fatal(err.Error(), 1) fatal(err.Error(), 1)
} }
if context.Bool("attach") { state = s
go func() { }
io.Copy(stdin, os.Stdin) if err := attachStdio(resp.Stdin, resp.Stdout, resp.Stderr); err != nil {
if state != nil { fatal(err.Error(), 1)
term.RestoreTerminal(os.Stdin.Fd(), state) }
} }
stdin.Close() if context.Bool("attach") {
}() restoreAndCloseStdin := func() {
for { if state != nil {
e, err := events.Recv() term.RestoreTerminal(os.Stdin.Fd(), state)
if err != nil {
fatal(err.Error(), 1)
}
if e.Pid == r.Pid && e.Type == "exit" {
os.Exit(int(e.Status))
}
}
} }
*/ stdin.Close()
}
go func() {
io.Copy(stdin, os.Stdin)
restoreAndCloseStdin()
}()
if err := waitForExit(c, context.String("id"), context.String("pid"), restoreAndCloseStdin); err != nil {
fatal(err.Error(), 1)
}
}
}, },
} }
@ -407,7 +403,7 @@ var statsCommand = cli.Command{
}, },
} }
func waitForExit(c types.APIClient, id string, closer func()) error { func waitForExit(c types.APIClient, id, pid string, closer func()) error {
events, err := c.Events(netcontext.Background(), &types.EventsRequest{}) events, err := c.Events(netcontext.Background(), &types.EventsRequest{})
if err != nil { if err != nil {
return err return err
@ -419,7 +415,7 @@ func waitForExit(c types.APIClient, id string, closer func()) error {
events, _ = c.Events(netcontext.Background(), &types.EventsRequest{}) events, _ = c.Events(netcontext.Background(), &types.EventsRequest{})
continue continue
} }
if e.Id == id && e.Type == "exit" && e.Pid == "init" { if e.Id == id && e.Type == "exit" && e.Pid == pid {
closer() closer()
os.Exit(int(e.Status)) os.Exit(int(e.Status))
} }

View file

@ -1,97 +1,17 @@
package runtime package runtime
import ( import (
"io" "encoding/json"
"io/ioutil"
"os" "os"
"time" "os/exec"
"path/filepath"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/opencontainers/specs" "github.com/opencontainers/specs"
) )
type Process interface {
io.Closer
// ID of the process.
// This is either "init" when it is the container's init process or
// it is a user provided id for the process similar to the container id
ID() string
// Stdin returns the path the the processes stdin fifo
Stdin() string
// Stdout returns the path the the processes stdout fifo
Stdout() string
// Stderr returns the path the the processes stderr fifo
Stderr() string
// ExitFD returns the fd the provides an event when the process exits
ExitFD() int
// ExitStatus returns the exit status of the process or an error if it
// has not exited
ExitStatus() (int, error)
Spec() specs.Process
// Signal sends the provided signal to the process
Signal(os.Signal) error
// Container returns the container that the process belongs to
Container() Container
}
type State string
const (
Paused = State("paused")
Running = State("running")
)
type Console interface {
io.ReadWriter
io.Closer
}
type IO struct {
Stdin io.WriteCloser
Stdout io.ReadCloser
Stderr io.ReadCloser
}
func (i *IO) Close() error {
var oerr error
for _, c := range []io.Closer{
i.Stdin,
i.Stdout,
i.Stderr,
} {
if c != nil {
if err := c.Close(); oerr == nil {
oerr = err
}
}
}
return oerr
}
type Stat struct {
// Timestamp is the time that the statistics where collected
Timestamp time.Time
// Data is the raw stats
// TODO: it is currently an interface because we don't know what type of exec drivers
// we will have or what the structure should look like at the moment os the containers
// can return what they want and we could marshal to json or whatever.
Data interface{}
}
type Checkpoint struct {
// Timestamp is the time that checkpoint happened
Timestamp time.Time
// Name is the name of the checkpoint
Name string
// Tcp checkpoints open tcp connections
Tcp bool
// UnixSockets persists unix sockets in the checkpoint
UnixSockets bool
// Shell persists tty sessions in the checkpoint
Shell bool
// Exit exits the container after the checkpoint is finished
Exit bool
}
type Container interface { type Container interface {
// ID returns the container ID // ID returns the container ID
ID() string ID() string
@ -99,10 +19,10 @@ type Container interface {
Path() string Path() string
// Start starts the init process of the container // Start starts the init process of the container
Start() (Process, error) Start() (Process, error)
// Exec starts another process in an existing container
Exec(string, specs.Process) (Process, error)
// Delete removes the container's state and any resources // Delete removes the container's state and any resources
Delete() error Delete() error
// Pid returns the container's init process id
// Pid() (int, error)
// Processes returns all the containers processes that have been added // Processes returns all the containers processes that have been added
Processes() ([]Process, error) Processes() ([]Process, error)
// State returns the containers runtime state // State returns the containers runtime state
@ -111,6 +31,7 @@ type Container interface {
Resume() error Resume() error
// Pause pauses a running container // Pause pauses a running container
Pause() error Pause() error
RemoveProcess(string) error
// Checkpoints returns all the checkpoints for a container // Checkpoints returns all the checkpoints for a container
// Checkpoints() ([]Checkpoint, error) // Checkpoints() ([]Checkpoint, error)
// Checkpoint creates a new checkpoint // Checkpoint creates a new checkpoint
@ -124,3 +45,183 @@ type Container interface {
// OOM signals the channel if the container received an OOM notification // OOM signals the channel if the container received an OOM notification
// OOM() (<-chan struct{}, error) // OOM() (<-chan struct{}, error)
} }
// New returns a new container
func New(root, id, bundle string) (Container, error) {
c := &container{
root: root,
id: id,
bundle: bundle,
processes: make(map[string]*process),
}
if err := os.Mkdir(filepath.Join(root, id), 0755); err != nil {
return nil, err
}
f, err := os.Create(filepath.Join(root, id, StateFile))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(state{
Bundle: bundle,
}); err != nil {
return nil, err
}
return c, nil
}
func Load(root, id string) (Container, error) {
var s state
f, err := os.Open(filepath.Join(root, id, StateFile))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&s); err != nil {
return nil, err
}
c := &container{
root: root,
id: id,
bundle: s.Bundle,
processes: make(map[string]*process),
}
dirs, err := ioutil.ReadDir(filepath.Join(root, id))
if err != nil {
return nil, err
}
for _, d := range dirs {
if !d.IsDir() {
continue
}
pid := d.Name()
s, err := readProcessSpec(filepath.Join(root, id, pid))
if err != nil {
return nil, err
}
p, err := loadProcess(filepath.Join(root, id, pid), pid, c, *s)
if err != nil {
logrus.WithField("id", id).WithField("pid", pid).Debug("containerd: error loading process %s", err)
continue
}
c.processes[pid] = p
}
return c, nil
}
func readProcessSpec(dir string) (*specs.Process, error) {
f, err := os.Open(filepath.Join(dir, "process.json"))
if err != nil {
return nil, err
}
defer f.Close()
var s specs.Process
if err := json.NewDecoder(f).Decode(&s); err != nil {
return nil, err
}
return &s, nil
}
type container struct {
// path to store runtime state information
root string
id string
bundle string
processes map[string]*process
}
func (c *container) ID() string {
return c.id
}
func (c *container) Path() string {
return c.bundle
}
func (c *container) Start() (Process, error) {
processRoot := filepath.Join(c.root, c.id, InitProcessID)
if err := os.MkdirAll(processRoot, 0755); err != nil {
return nil, err
}
cmd := exec.Command("containerd-shim", c.id, c.bundle)
cmd.Dir = processRoot
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
spec, err := c.readSpec()
if err != nil {
return nil, err
}
p, err := newProcess(processRoot, InitProcessID, c, spec.Process)
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
c.processes[InitProcessID] = p
return p, nil
}
func (c *container) Exec(pid string, spec specs.Process) (Process, error) {
processRoot := filepath.Join(c.root, c.id, pid)
if err := os.MkdirAll(processRoot, 0755); err != nil {
return nil, err
}
cmd := exec.Command("containerd-shim", "-exec", c.id, c.bundle)
cmd.Dir = processRoot
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
p, err := newProcess(processRoot, pid, c, spec)
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
c.processes[pid] = p
return p, nil
}
func (c *container) readSpec() (*specs.LinuxSpec, error) {
var spec specs.LinuxSpec
f, err := os.Open(filepath.Join(c.bundle, "config.json"))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&spec); err != nil {
return nil, err
}
return &spec, nil
}
func (c *container) Pause() error {
return exec.Command("runc", "--id", c.id, "pause").Run()
}
func (c *container) Resume() error {
return exec.Command("runc", "--id", c.id, "resume").Run()
}
func (c *container) State() State {
return Running
}
func (c *container) Delete() error {
return os.RemoveAll(filepath.Join(c.root, c.id))
}
func (c *container) Processes() ([]Process, error) {
out := []Process{}
for _, p := range c.processes {
out = append(out, p)
}
return out, nil
}
func (c *container) RemoveProcess(pid string) error {
delete(c.processes, pid)
return nil
}

View file

@ -1,172 +0,0 @@
package runtime
import (
"encoding/json"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/opencontainers/specs"
)
const (
ExitFile = "exit"
ExitStatusFile = "exitStatus"
StateFile = "state.json"
InitProcessID = "init"
)
type state struct {
Bundle string `json:"bundle"`
}
// New returns a new container
func New(root, id, bundle string) (Container, error) {
c := &container{
root: root,
id: id,
bundle: bundle,
processes: make(map[string]*process),
}
if err := os.Mkdir(filepath.Join(root, id), 0755); err != nil {
return nil, err
}
f, err := os.Create(filepath.Join(root, id, StateFile))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(state{
Bundle: bundle,
}); err != nil {
return nil, err
}
return c, nil
}
func Load(root, id string) (Container, error) {
var s state
f, err := os.Open(filepath.Join(root, id, StateFile))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&s); err != nil {
return nil, err
}
c := &container{
root: root,
id: id,
bundle: s.Bundle,
processes: make(map[string]*process),
}
dirs, err := ioutil.ReadDir(filepath.Join(root, id))
if err != nil {
return nil, err
}
for _, d := range dirs {
if !d.IsDir() {
continue
}
pid := d.Name()
// TODO: get the process spec from a state file in the process dir
p, err := loadProcess(filepath.Join(root, id, pid), pid, c, specs.Process{})
if err != nil {
if err == ErrProcessExited {
logrus.WithField("id", id).WithField("pid", pid).Debug("containerd: process exited while away")
// TODO: fire events to do the removal
if err := os.RemoveAll(filepath.Join(root, id, pid)); err != nil {
logrus.WithField("error", err).Warn("containerd: remove process state")
}
continue
}
return nil, err
}
c.processes[pid] = p
}
if len(c.processes) == 0 {
return nil, ErrContainerExited
}
return c, nil
}
type container struct {
// path to store runtime state information
root string
id string
bundle string
processes map[string]*process
}
func (c *container) ID() string {
return c.id
}
func (c *container) Path() string {
return c.bundle
}
func (c *container) Start() (Process, error) {
processRoot := filepath.Join(c.root, c.id, InitProcessID)
if err := os.MkdirAll(processRoot, 0755); err != nil {
return nil, err
}
cmd := exec.Command("containerd-shim", processRoot, c.id)
cmd.Dir = c.bundle
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
spec, err := c.readSpec()
if err != nil {
return nil, err
}
p, err := newProcess(processRoot, InitProcessID, c, spec.Process)
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
c.processes[InitProcessID] = p
return p, nil
}
func (c *container) readSpec() (*specs.LinuxSpec, error) {
var spec specs.LinuxSpec
f, err := os.Open(filepath.Join(c.bundle, "config.json"))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&spec); err != nil {
return nil, err
}
return &spec, nil
}
func (c *container) Pause() error {
return errNotImplemented
}
func (c *container) Resume() error {
return errNotImplemented
}
func (c *container) State() State {
return Running
}
func (c *container) Delete() error {
return os.RemoveAll(filepath.Join(c.root, c.id))
}
func (c *container) Processes() ([]Process, error) {
out := []Process{}
for _, p := range c.processes {
out = append(out, p)
}
return out, nil
}

View file

@ -1,6 +1,8 @@
package runtime package runtime
import ( import (
"encoding/json"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -10,6 +12,31 @@ import (
"github.com/opencontainers/specs" "github.com/opencontainers/specs"
) )
type Process interface {
io.Closer
// ID of the process.
// This is either "init" when it is the container's init process or
// it is a user provided id for the process similar to the container id
ID() string
// Stdin returns the path the the processes stdin fifo
Stdin() string
// Stdout returns the path the the processes stdout fifo
Stdout() string
// Stderr returns the path the the processes stderr fifo
Stderr() string
// ExitFD returns the fd the provides an event when the process exits
ExitFD() int
// ExitStatus returns the exit status of the process or an error if it
// has not exited
ExitStatus() (int, error)
Spec() specs.Process
// Signal sends the provided signal to the process
Signal(os.Signal) error
// Container returns the container that the process belongs to
Container() Container
}
func newProcess(root, id string, c *container, s specs.Process) (*process, error) { func newProcess(root, id string, c *container, s specs.Process) (*process, error) {
p := &process{ p := &process{
root: root, root: root,
@ -17,6 +44,14 @@ func newProcess(root, id string, c *container, s specs.Process) (*process, error
container: c, container: c,
spec: s, spec: s,
} }
f, err := os.Create(filepath.Join(root, "process.json"))
if err != nil {
return nil, err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(s); err != nil {
return nil, err
}
// create fifo's for the process // create fifo's for the process
for name, fd := range map[string]*string{ for name, fd := range map[string]*string{
"stdin": &p.stdin, "stdin": &p.stdin,
@ -58,7 +93,7 @@ func loadProcess(root, id string, c *container, s specs.Process) (*process, erro
} }
return nil, err return nil, err
} }
return nil, ErrProcessExited return p, nil
} }
func getExitPipe(path string) (*os.File, error) { func getExitPipe(path string) (*os.File, error) {

View file

@ -1,6 +1,9 @@
package runtime package runtime
import "errors" import (
"errors"
"time"
)
var ( var (
ErrNotChildProcess = errors.New("containerd: not a child process for container") ErrNotChildProcess = errors.New("containerd: not a child process for container")
@ -14,3 +17,46 @@ var (
errNotImplemented = errors.New("containerd: not implemented") errNotImplemented = errors.New("containerd: not implemented")
) )
const (
ExitFile = "exit"
ExitStatusFile = "exitStatus"
StateFile = "state.json"
InitProcessID = "init"
)
type State string
const (
Paused = State("paused")
Running = State("running")
)
type state struct {
Bundle string `json:"bundle"`
}
type Stat struct {
// Timestamp is the time that the statistics where collected
Timestamp time.Time
// Data is the raw stats
// TODO: it is currently an interface because we don't know what type of exec drivers
// we will have or what the structure should look like at the moment os the containers
// can return what they want and we could marshal to json or whatever.
Data interface{}
}
type Checkpoint struct {
// Timestamp is the time that checkpoint happened
Timestamp time.Time
// Name is the name of the checkpoint
Name string
// Tcp checkpoints open tcp connections
Tcp bool
// UnixSockets persists unix sockets in the checkpoint
UnixSockets bool
// Shell persists tty sessions in the checkpoint
Shell bool
// Exit exits the container after the checkpoint is finished
Exit bool
}

View file

@ -1,5 +1,7 @@
package supervisor package supervisor
import "time"
type AddProcessEvent struct { type AddProcessEvent struct {
s *Supervisor s *Supervisor
} }
@ -7,32 +9,23 @@ type AddProcessEvent struct {
// TODO: add this to worker for concurrent starts??? maybe not because of races where the container // TODO: add this to worker for concurrent starts??? maybe not because of races where the container
// could be stopped and removed... // could be stopped and removed...
func (h *AddProcessEvent) Handle(e *Event) error { func (h *AddProcessEvent) Handle(e *Event) error {
/* start := time.Now()
start := time.Now() ci, ok := h.s.containers[e.ID]
ci, ok := h.s.containers[e.ID] if !ok {
if !ok { return ErrContainerNotFound
return ErrContainerNotFound }
} process, err := ci.container.Exec(e.Pid, *e.ProcessSpec)
p, io, err := h.s.runtime.StartProcess(ci.container, *e.Process, e.Console) if err != nil {
if err != nil { return err
return err }
} if err := h.s.monitorProcess(process); err != nil {
if e.Pid, err = p.Pid(); err != nil { return err
return err }
} ExecProcessTimer.UpdateSince(start)
h.s.processes[e.Pid] = &containerInfo{ e.StartResponse <- StartResponse{
container: ci.container, Stdin: process.Stdin(),
} Stdout: process.Stdout(),
l, err := h.s.copyIO(e.Stdin, e.Stdout, e.Stderr, io) Stderr: process.Stderr(),
if err != nil { }
// log the error but continue with the other commands
logrus.WithFields(logrus.Fields{
"error": err,
"id": e.ID,
}).Error("log stdio")
}
h.s.processes[e.Pid].copier = l
ExecProcessTimer.UpdateSince(start)
*/
return nil return nil
} }

View file

@ -17,11 +17,6 @@ func (h *DeleteEvent) Handle(e *Event) error {
if err := h.deleteContainer(i.container); err != nil { if err := h.deleteContainer(i.container); err != nil {
logrus.WithField("error", err).Error("containerd: deleting container") logrus.WithField("error", err).Error("containerd: deleting container")
} }
if i.copier != nil {
if err := i.copier.Close(); err != nil {
logrus.WithField("error", err).Error("containerd: close container copier")
}
}
h.s.notifySubscribers(&Event{ h.s.notifySubscribers(&Event{
Type: ExitEventType, Type: ExitEventType,
ID: e.ID, ID: e.ID,

View file

@ -25,7 +25,9 @@ func (h *ExitEvent) Handle(e *Event) error {
if proc.ID() != runtime.InitProcessID { if proc.ID() != runtime.InitProcessID {
ne := NewEvent(ExecExitEventType) ne := NewEvent(ExecExitEventType)
ne.ID = proc.Container().ID() ne.ID = proc.Container().ID()
ne.Pid = proc.ID()
ne.Status = status ne.Status = status
ne.Process = proc
h.s.SendEvent(ne) h.s.SendEvent(ne)
return nil return nil
@ -51,17 +53,11 @@ type ExecExitEvent struct {
} }
func (h *ExecExitEvent) Handle(e *Event) error { func (h *ExecExitEvent) Handle(e *Event) error {
container := e.Process.Container()
// exec process: we remove this process without notifying the main event loop // exec process: we remove this process without notifying the main event loop
/* if err := container.RemoveProcess(e.Pid); err != nil {
info := h.s.processes[e.Pid] logrus.WithField("error", err).Error("containerd: find container for pid")
if err := info.container.RemoveProcess(e.Pid); err != nil { }
logrus.WithField("error", err).Error("containerd: find container for pid") h.s.notifySubscribers(e)
}
if err := info.copier.Close(); err != nil {
logrus.WithField("error", err).Error("containerd: close process IO")
}
delete(h.s.processes, e.Pid)
h.s.notifySubscribers(e)
*/
return nil return nil
} }

View file

@ -1,66 +0,0 @@
package supervisor
import (
"io"
"os"
)
type ioConfig struct {
StdoutPath string
StderrPath string
StdinPath string
Stdin io.WriteCloser
Stdout io.ReadCloser
Stderr io.ReadCloser
}
func newCopier(i *ioConfig) (*copier, error) {
l := &copier{
config: i,
}
if i.StdinPath != "" {
f, err := os.OpenFile(i.StdinPath, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
l.closers = append(l.closers, f)
go func() {
io.Copy(i.Stdin, f)
i.Stdin.Close()
}()
}
if i.StdoutPath != "" {
f, err := os.OpenFile(i.StdoutPath, os.O_RDWR, 0)
if err != nil {
return nil, err
}
l.closers = append(l.closers, f)
go io.Copy(f, i.Stdout)
}
if i.StderrPath != "" {
f, err := os.OpenFile(i.StderrPath, os.O_RDWR, 0)
if err != nil {
return nil, err
}
l.closers = append(l.closers, f)
go io.Copy(f, i.Stderr)
}
return l, nil
}
type copier struct {
config *ioConfig
closers []io.Closer
}
func (l *copier) Close() (err error) {
for _, c := range append(l.closers, l.config.Stdin, l.config.Stdout, l.config.Stderr) {
if c != nil {
if cerr := c.Close(); err == nil {
err = cerr
}
}
}
return err
}

View file

@ -11,6 +11,7 @@ var (
EventsCounter = metrics.NewCounter() EventsCounter = metrics.NewCounter()
ExecProcessTimer = metrics.NewTimer() ExecProcessTimer = metrics.NewTimer()
ExitProcessTimer = metrics.NewTimer() ExitProcessTimer = metrics.NewTimer()
EpollFdCounter = metrics.NewCounter()
) )
func Metrics() map[string]interface{} { func Metrics() map[string]interface{} {
@ -23,5 +24,6 @@ func Metrics() map[string]interface{} {
"events": EventsCounter, "events": EventsCounter,
"exec-process-time": ExecProcessTimer, "exec-process-time": ExecProcessTimer,
"exit-process-time": ExitProcessTimer, "exit-process-time": ExitProcessTimer,
"epoll-fds": EpollFdCounter,
} }
} }

View file

@ -44,6 +44,7 @@ func (m *Monitor) Monitor(p runtime.Process) error {
if err := syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil { if err := syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
return err return err
} }
EpollFdCounter.Inc(1)
m.processes[fd] = p m.processes[fd] = p
return nil return nil
} }
@ -75,6 +76,7 @@ func (m *Monitor) start() {
}); err != nil { }); err != nil {
logrus.WithField("error", err).Fatal("containerd: epoll remove fd") logrus.WithField("error", err).Fatal("containerd: epoll remove fd")
} }
EpollFdCounter.Dec(1)
if err := proc.Close(); err != nil { if err := proc.Close(); err != nil {
logrus.WithField("error", err).Error("containerd: close process IO") logrus.WithField("error", err).Error("containerd: close process IO")
} }

View file

@ -5,20 +5,18 @@ type SignalEvent struct {
} }
func (h *SignalEvent) Handle(e *Event) error { func (h *SignalEvent) Handle(e *Event) error {
/* i, ok := h.s.containers[e.ID]
i, ok := h.s.containers[e.ID] if !ok {
if !ok { return ErrContainerNotFound
return ErrContainerNotFound }
processes, err := i.container.Processes()
if err != nil {
return err
}
for _, p := range processes {
if p.ID() == e.Pid {
return p.Signal(e.Signal)
} }
processes, err := i.container.Processes() }
if err != nil {
return err
}
for _, p := range processes {
if pid, err := p.Pid(); err == nil && pid == e.Pid {
return p.Signal(e.Signal)
}
}
*/
return ErrProcessNotFound return ErrProcessNotFound
} }

69
supervisor/sort_test.go Normal file
View file

@ -0,0 +1,69 @@
package supervisor
import (
"os"
"sort"
"testing"
"github.com/docker/containerd/runtime"
"github.com/opencontainers/specs"
)
type testProcess struct {
id string
}
func (p *testProcess) ID() string {
return p.id
}
func (p *testProcess) Stdin() string {
return ""
}
func (p *testProcess) Stdout() string {
return ""
}
func (p *testProcess) Stderr() string {
return ""
}
func (p *testProcess) ExitFD() int {
return -1
}
func (p *testProcess) ExitStatus() (int, error) {
return -1, nil
}
func (p *testProcess) Container() runtime.Container {
return nil
}
func (p *testProcess) Spec() specs.Process {
return specs.Process{}
}
func (p *testProcess) Signal(os.Signal) error {
return nil
}
func (p *testProcess) Close() error {
return nil
}
func TestSortProcesses(t *testing.T) {
p := []runtime.Process{
&testProcess{"ls"},
&testProcess{"other"},
&testProcess{"init"},
&testProcess{"other2"},
}
s := &processSorter{p}
sort.Sort(s)
if id := p[len(p)-1].ID(); id != "init" {
t.Fatalf("expected init but received %q", id)
}
}

View file

@ -3,7 +3,7 @@ package supervisor
import ( import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "sort"
"sync" "sync"
"time" "time"
@ -76,7 +76,6 @@ func New(stateDir string, tasks chan *StartTask, oom bool) (*Supervisor, error)
type containerInfo struct { type containerInfo struct {
container runtime.Container container runtime.Container
copier *copier
} }
type Supervisor struct { type Supervisor struct {
@ -195,14 +194,6 @@ func (s *Supervisor) restore() error {
id := d.Name() id := d.Name()
container, err := runtime.Load(s.stateDir, id) container, err := runtime.Load(s.stateDir, id)
if err != nil { if err != nil {
if err == runtime.ErrContainerExited {
logrus.WithField("id", id).Debug("containerd: container exited while away")
// TODO: fire events to do the removal
if err := os.RemoveAll(filepath.Join(s.stateDir, id)); err != nil {
logrus.WithField("error", err).Warn("containerd: remove container state")
}
continue
}
return err return err
} }
processes, err := container.Processes() processes, err := container.Processes()
@ -214,11 +205,42 @@ func (s *Supervisor) restore() error {
container: container, container: container,
} }
logrus.WithField("id", id).Debug("containerd: container restored") logrus.WithField("id", id).Debug("containerd: container restored")
var exitedProcesses []runtime.Process
for _, p := range processes { for _, p := range processes {
if err := s.monitorProcess(p); err != nil { if _, err := p.ExitStatus(); err == nil {
return err exitedProcesses = append(exitedProcesses, p)
} else {
if err := s.monitorProcess(p); err != nil {
return err
}
}
}
if len(exitedProcesses) > 0 {
// sort processes so that init is fired last because that is how the kernel sends the
// exit events
sort.Sort(&processSorter{exitedProcesses})
for _, p := range exitedProcesses {
e := NewEvent(ExitEventType)
e.Process = p
s.SendEvent(e)
} }
} }
} }
return nil return nil
} }
type processSorter struct {
processes []runtime.Process
}
func (s *processSorter) Len() int {
return len(s.processes)
}
func (s *processSorter) Swap(i, j int) {
s.processes[i], s.processes[j] = s.processes[j], s.processes[i]
}
func (s *processSorter) Less(i, j int) bool {
return s.processes[j].ID() == "init"
}

View file

@ -27,17 +27,17 @@ func (h *UpdateEvent) Handle(e *Event) error {
} }
} }
if e.Signal != nil { if e.Signal != nil {
/* // signal the pid1/main process of the container
// signal the pid1/main process of the container processes, err := container.Processes()
processes, err := container.Processes() if err != nil {
if err != nil { return err
return err }
for _, p := range processes {
if p.ID() == runtime.InitProcessID {
return p.Signal(e.Signal)
} }
if len(processes) == 0 { }
return ErrProcessNotFound return ErrProcessNotFound
}
return processes[0].Signal(e.Signal)
*/
} }
return nil return nil
} }

View file

@ -15,7 +15,6 @@ type Worker interface {
type StartTask struct { type StartTask struct {
Container runtime.Container Container runtime.Container
Checkpoint string Checkpoint string
IO *runtime.IO
Stdin string Stdin string
Stdout string Stdout string
Stderr string Stderr string

View file

@ -1,3 +1,3 @@
package containerd package containerd
const Version = "0.0.4" const Version = "0.0.5"