diff --git a/api/grpc/server/server.go b/api/grpc/server/server.go index e6edcb5..bbc45fc 100644 --- a/api/grpc/server/server.go +++ b/api/grpc/server/server.go @@ -2,6 +2,7 @@ package server import ( "errors" + "fmt" "syscall" "google.golang.org/grpc" @@ -75,18 +76,27 @@ func (s *apiServer) AddProcess(ctx context.Context, r *types.AddProcessRequest) 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.ID = r.Id + e.Pid = r.Pid e.ProcessSpec = process - e.Console = r.Console - e.Stdin = r.Stdin - e.Stdout = r.Stdout - e.Stderr = r.Stderr + e.StartResponse = make(chan supervisor.StartResponse, 1) s.sv.SendEvent(e) if err := <-e.Err; err != nil { 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) { diff --git a/api/grpc/types/api.pb.go b/api/grpc/types/api.pb.go index 10b0e20..e6a48c0 100644 --- a/api/grpc/types/api.pb.go +++ b/api/grpc/types/api.pb.go @@ -65,7 +65,7 @@ var _ = math.Inf type CreateContainerRequest struct { Id string `protobuf:"bytes,1,opt,name=id" json:"id,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{} } @@ -74,9 +74,10 @@ func (*CreateContainerRequest) ProtoMessage() {} func (*CreateContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } type CreateContainerResponse 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"` + Pid uint32 `protobuf:"varint,1,opt,name=pid" json:"pid,omitempty"` + Stdin string `protobuf:"bytes,2,opt,name=stdin" json:"stdin,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{} } @@ -110,10 +111,7 @@ type AddProcessRequest struct { Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"` Cwd string `protobuf:"bytes,6,opt,name=cwd" json:"cwd,omitempty"` - Stdin string `protobuf:"bytes,7,opt,name=stdin" json:"stdin,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"` + Pid string `protobuf:"bytes,7,opt,name=pid" json:"pid,omitempty"` } func (m *AddProcessRequest) Reset() { *m = AddProcessRequest{} } @@ -140,6 +138,9 @@ func (*User) ProtoMessage() {} func (*User) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } 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{} } @@ -1084,94 +1085,94 @@ var _API_serviceDesc = grpc.ServiceDesc{ var fileDescriptor0 = []byte{ // 1440 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x58, 0xd9, 0x72, 0xdc, 0x44, - 0x17, 0xf6, 0xec, 0x33, 0x67, 0x16, 0xdb, 0xf2, 0x92, 0xf1, 0xfc, 0x7f, 0x88, 0x11, 0x81, 0xa4, - 0xa8, 0x94, 0x2b, 0x38, 0x2c, 0x21, 0x5c, 0x40, 0x70, 0x52, 0x09, 0x54, 0x02, 0xae, 0xc4, 0xa6, - 0x8a, 0x1b, 0xa6, 0x64, 0xa9, 0x19, 0x8b, 0xd1, 0x48, 0x42, 0x6a, 0x79, 0x79, 0x05, 0x9e, 0x87, - 0xe2, 0x01, 0xa8, 0xe2, 0x9e, 0xe7, 0xe0, 0x29, 0x38, 0xdd, 0x7d, 0xd4, 0x5a, 0x66, 0x09, 0x5c, - 0x70, 0x33, 0x55, 0xdd, 0x7d, 0xce, 0x77, 0xbe, 0xb3, 0xaa, 0x7b, 0xa0, 0x63, 0x85, 0xee, 0x41, - 0x18, 0x05, 0x3c, 0x30, 0x1a, 0xfc, 0x3a, 0x64, 0xb1, 0xf9, 0x02, 0x76, 0x8f, 0x22, 0x66, 0x71, - 0x76, 0x14, 0xf8, 0xdc, 0x72, 0x7d, 0x16, 0xbd, 0x62, 0x3f, 0x27, 0x2c, 0xe6, 0x06, 0x40, 0xd5, - 0x75, 0x86, 0x95, 0xfd, 0xca, 0xdd, 0x8e, 0x81, 0x8b, 0xb3, 0xc4, 0x77, 0x3c, 0x76, 0x6c, 0xf1, - 0xf3, 0x61, 0x35, 0xdd, 0xb3, 0xcf, 0x99, 0x3d, 0x0d, 0x03, 0xd7, 0xe7, 0xc3, 0x9a, 0xd8, 0x33, - 0x9f, 0xc3, 0x8d, 0x39, 0xb4, 0x38, 0x0c, 0xfc, 0x98, 0x19, 0x7d, 0x68, 0xc4, 0xdc, 0x71, 0x7d, - 0x42, 0x1c, 0x40, 0x13, 0x97, 0x41, 0xc2, 0x09, 0x4d, 0xad, 0x59, 0x14, 0x11, 0xd2, 0x43, 0xe8, - 0xbf, 0x76, 0x27, 0xbe, 0xe5, 0x2d, 0xa2, 0xd3, 0x85, 0x5a, 0x88, 0x8b, 0x4c, 0x53, 0x4a, 0x4a, - 0xcd, 0xbe, 0xb9, 0x01, 0x83, 0x54, 0x53, 0x99, 0x36, 0x7f, 0xad, 0xc0, 0xe6, 0x63, 0xc7, 0x39, - 0x8e, 0x02, 0x9b, 0xc5, 0xf1, 0x22, 0xc0, 0x0d, 0x68, 0x73, 0x16, 0xcd, 0x5c, 0x81, 0x22, 0x50, - 0xdb, 0xc6, 0x1e, 0xd4, 0x93, 0x98, 0x29, 0x36, 0xdd, 0xc3, 0xee, 0x81, 0x8c, 0xd6, 0xc1, 0x29, - 0x6e, 0x19, 0x3d, 0xa8, 0x5b, 0xd1, 0x24, 0x1e, 0xd6, 0xf7, 0x6b, 0x8a, 0x0b, 0xf3, 0x2f, 0x86, - 0x8d, 0x74, 0x61, 0x5f, 0x3a, 0xc3, 0xa6, 0x04, 0xd5, 0x1e, 0xb7, 0x4a, 0x1e, 0xb7, 0x4b, 0x1e, - 0x77, 0xe4, 0x7a, 0x1d, 0x5a, 0x36, 0xd2, 0x0d, 0x3c, 0x36, 0x04, 0x0a, 0x41, 0x5d, 0xda, 0x43, - 0xd0, 0x84, 0x98, 0xf6, 0xc5, 0x62, 0x42, 0xae, 0xf7, 0x8d, 0x5d, 0x18, 0x58, 0x8e, 0xe3, 0x72, - 0x37, 0x40, 0xe2, 0xcf, 0x5c, 0x27, 0x46, 0xba, 0x35, 0x0c, 0xc1, 0x36, 0x18, 0x79, 0x7f, 0x29, - 0x0c, 0x2f, 0x74, 0x72, 0x74, 0xda, 0x16, 0xc5, 0xe2, 0xdd, 0x42, 0x5e, 0xab, 0xd2, 0xff, 0x4d, - 0xf2, 0x3f, 0xd3, 0x34, 0x47, 0x30, 0x9c, 0x47, 0x23, 0x4b, 0x0f, 0xe0, 0xc6, 0x13, 0xe6, 0xb1, - 0x37, 0x59, 0xc2, 0x40, 0xfa, 0xd6, 0x8c, 0xa9, 0x3c, 0x0a, 0xc0, 0x79, 0x25, 0x02, 0x7c, 0x07, - 0x76, 0x5e, 0xb8, 0x31, 0x5f, 0x09, 0x67, 0x7e, 0x0f, 0x90, 0x09, 0x68, 0x70, 0x6d, 0x8a, 0x5d, - 0xb9, 0x9c, 0x92, 0x8b, 0x41, 0xe4, 0x76, 0x28, 0x73, 0xdb, 0x36, 0xb6, 0xa0, 0x9b, 0xf8, 0xee, - 0xd5, 0xeb, 0xc0, 0x9e, 0x32, 0x2e, 0xb2, 0x2a, 0x36, 0x45, 0xee, 0xce, 0x99, 0xe7, 0x61, 0x5e, - 0x71, 0x69, 0x7e, 0x01, 0xbb, 0x65, 0xfb, 0x54, 0xd6, 0xef, 0x41, 0x37, 0x8b, 0x56, 0x8c, 0xd6, - 0x6a, 0x8b, 0xc3, 0x35, 0x80, 0xde, 0x6b, 0x8e, 0xd1, 0x22, 0xe2, 0xe6, 0x3e, 0x0c, 0x74, 0x8f, - 0xc8, 0x03, 0x55, 0x0f, 0x16, 0x4f, 0x62, 0x72, 0x67, 0x0a, 0x2d, 0xca, 0x60, 0x5a, 0xef, 0xff, - 0x5d, 0xad, 0x9a, 0x1e, 0x74, 0x34, 0x9d, 0xe5, 0x39, 0x2a, 0xcd, 0x01, 0xd9, 0xa9, 0xc6, 0xdb, - 0xd0, 0x09, 0x15, 0x4f, 0xa6, 0xec, 0x74, 0x0f, 0x07, 0x44, 0x21, 0xe5, 0x9f, 0xb9, 0xd6, 0x90, - 0xd6, 0xee, 0x40, 0xeb, 0xa5, 0x65, 0x9f, 0xa3, 0x31, 0x81, 0x6f, 0x87, 0xe4, 0x73, 0x5f, 0x08, - 0xce, 0xd8, 0x2c, 0x88, 0xae, 0xa5, 0xbd, 0xba, 0xf9, 0x1d, 0x4e, 0x01, 0x15, 0x35, 0x0a, 0xf7, - 0x6d, 0x2c, 0xce, 0x94, 0x67, 0x1a, 0xed, 0x8d, 0x34, 0xda, 0xda, 0x81, 0x5b, 0xd0, 0x9a, 0x29, - 0x7c, 0xaa, 0xdf, 0x94, 0x10, 0x59, 0x35, 0x9f, 0xc0, 0xee, 0x69, 0xe8, 0xbc, 0x69, 0xea, 0x65, - 0x93, 0xa5, 0x9a, 0xb2, 0x23, 0x37, 0xd4, 0x8c, 0xda, 0x83, 0x1b, 0x73, 0x28, 0x54, 0xb0, 0xeb, - 0xd0, 0x7f, 0x7a, 0xc1, 0xb0, 0x22, 0xd2, 0x7c, 0xff, 0x59, 0x81, 0x86, 0xdc, 0x11, 0x1e, 0x0b, - 0x32, 0x64, 0x43, 0xd9, 0xcb, 0xcd, 0x40, 0x8d, 0xdf, 0x2f, 0x45, 0xbb, 0x9e, 0x1f, 0x7d, 0x8d, - 0x12, 0xc1, 0x96, 0x54, 0x40, 0xbf, 0x29, 0x15, 0x72, 0xc6, 0xcc, 0x27, 0xa2, 0x18, 0xbe, 0xce, - 0x92, 0xf0, 0x15, 0x27, 0x00, 0x2c, 0x9b, 0x00, 0xbf, 0x55, 0xa0, 0xf7, 0x0d, 0xe3, 0x97, 0x41, - 0x34, 0x15, 0x49, 0x8a, 0x4b, 0x2d, 0x87, 0x75, 0x1a, 0x5d, 0x8d, 0xcf, 0xae, 0x39, 0x96, 0x85, - 0xcc, 0xa6, 0xf0, 0x07, 0x77, 0x8e, 0x2d, 0xd5, 0x68, 0x35, 0xb9, 0xb7, 0x09, 0x9d, 0x57, 0x57, - 0x63, 0x9c, 0x82, 0x41, 0xa4, 0x7a, 0x4f, 0x8a, 0xe1, 0x96, 0x13, 0x05, 0x61, 0xc8, 0x94, 0xa7, - 0x75, 0x01, 0x76, 0x92, 0x82, 0x35, 0x53, 0x29, 0xdc, 0x09, 0x09, 0xac, 0x95, 0x82, 0x9d, 0x68, - 0xb0, 0x76, 0x4e, 0x2c, 0x05, 0xeb, 0xc8, 0xaa, 0x9a, 0x41, 0xfb, 0x28, 0x4c, 0x4e, 0x63, 0x6b, - 0xc2, 0x44, 0xf7, 0xf3, 0x80, 0x5b, 0xde, 0x38, 0x11, 0x4b, 0x49, 0xbd, 0x6e, 0x6c, 0x43, 0x2f, - 0x64, 0x11, 0xd6, 0x25, 0xed, 0x56, 0x31, 0x50, 0x75, 0xe3, 0x7f, 0xb0, 0x25, 0x97, 0x63, 0xd7, - 0x1f, 0x4f, 0x59, 0xe4, 0x33, 0x6f, 0x16, 0x38, 0x8c, 0xfc, 0xd8, 0x83, 0x4d, 0x7d, 0x28, 0x9a, - 0x51, 0x1e, 0x49, 0x7f, 0xcc, 0x13, 0x18, 0x9c, 0x9c, 0xe3, 0x37, 0x97, 0x7b, 0xae, 0x3f, 0x79, - 0x62, 0x71, 0x4b, 0x8c, 0x7a, 0xc4, 0x77, 0x03, 0x27, 0x26, 0x83, 0xa8, 0xcd, 0x95, 0x08, 0x73, - 0xc6, 0xe9, 0x91, 0x0a, 0x1a, 0xce, 0xf8, 0xec, 0x88, 0xbb, 0x33, 0x32, 0x68, 0xfe, 0x20, 0x9d, - 0x50, 0x81, 0x37, 0xa1, 0x93, 0x91, 0xad, 0xc8, 0x7c, 0xad, 0xa7, 0xf9, 0x4a, 0x1d, 0x3d, 0x80, - 0x75, 0xae, 0x59, 0x8c, 0xb1, 0x6a, 0x2d, 0xea, 0x8d, 0x1d, 0x92, 0x2c, 0x72, 0x34, 0x3f, 0x07, - 0x78, 0x29, 0x5b, 0x51, 0x32, 0xc6, 0x79, 0x98, 0x0f, 0x10, 0x06, 0x7a, 0x66, 0x5d, 0xe9, 0xe8, - 0x88, 0x2d, 0xf4, 0xe9, 0x47, 0xcb, 0xf5, 0x6c, 0xba, 0x0b, 0xd4, 0xcd, 0xbf, 0x2a, 0xd0, 0x55, - 0x08, 0x8a, 0x24, 0x42, 0xd8, 0xd8, 0x7e, 0x29, 0xc4, 0x7e, 0x8a, 0x58, 0xfc, 0xc2, 0xe4, 0x6c, - 0x62, 0x19, 0xc6, 0x97, 0x56, 0x48, 0x56, 0x6a, 0xcb, 0xc4, 0xee, 0x40, 0x4f, 0x65, 0x83, 0x04, - 0xeb, 0xcb, 0x04, 0xef, 0x89, 0xef, 0x31, 0x32, 0x91, 0xf3, 0xaf, 0x7b, 0x78, 0xb3, 0x20, 0x21, - 0x39, 0x1e, 0xc8, 0xdf, 0xa7, 0x3e, 0x8f, 0xae, 0x47, 0xf7, 0x00, 0xb2, 0x95, 0x68, 0xbb, 0x29, - 0xbb, 0xa6, 0xca, 0x46, 0x4f, 0x2e, 0x2c, 0x2f, 0x21, 0xcf, 0x1f, 0x55, 0x1f, 0x56, 0xcc, 0xaf, - 0x61, 0xfd, 0x4b, 0x6f, 0xea, 0x06, 0x39, 0x15, 0x94, 0x9a, 0x59, 0x3f, 0x05, 0x11, 0xf9, 0x2b, - 0x96, 0xae, 0x8f, 0x4b, 0x15, 0x2e, 0xec, 0xfb, 0x20, 0xa4, 0x09, 0xaa, 0xf1, 0x54, 0xbd, 0xfc, - 0x5e, 0x03, 0xc8, 0xc0, 0x8c, 0x47, 0x30, 0x72, 0x83, 0x31, 0x96, 0xd4, 0x85, 0x6b, 0x33, 0xd5, - 0x02, 0xe3, 0x88, 0xd9, 0x49, 0x14, 0xbb, 0x17, 0x8c, 0x46, 0xe0, 0x2e, 0xf9, 0x52, 0xe6, 0xf0, - 0x11, 0xec, 0x64, 0xba, 0x4e, 0x4e, 0xad, 0xba, 0x52, 0xed, 0x01, 0x6c, 0xa1, 0x1a, 0x0e, 0xae, - 0xa4, 0xa0, 0x54, 0x5b, 0xa9, 0xf4, 0x29, 0xec, 0xe5, 0x78, 0x8a, 0x4a, 0xcd, 0xa9, 0xd6, 0x57, - 0xaa, 0x7e, 0x0c, 0xbb, 0xa8, 0x7a, 0x69, 0xb9, 0xbc, 0xac, 0xd7, 0xf8, 0x07, 0x3c, 0x67, 0x2c, - 0x9a, 0x14, 0x78, 0x36, 0x57, 0x2a, 0x7d, 0x00, 0x9b, 0xa8, 0x54, 0xb2, 0xd3, 0x7a, 0x93, 0x4a, - 0xcc, 0x6c, 0x8e, 0x53, 0x25, 0xa7, 0xd2, 0x5e, 0xa5, 0x62, 0x3e, 0x86, 0xde, 0xf3, 0x64, 0xc2, - 0xb8, 0x77, 0xa6, 0xab, 0xff, 0xdf, 0x36, 0xd0, 0x2f, 0x55, 0xe8, 0x1e, 0x4d, 0xa2, 0x20, 0x09, - 0x0b, 0x5d, 0xae, 0x6a, 0x78, 0xae, 0xcb, 0x95, 0xcc, 0x5d, 0xe8, 0xa9, 0x0f, 0x28, 0x89, 0xa9, - 0xe6, 0x32, 0xe6, 0x4b, 0x5d, 0x5c, 0x5c, 0xce, 0x04, 0x67, 0x12, 0x2c, 0xb6, 0x57, 0xae, 0xfc, - 0x3e, 0x83, 0xfe, 0xb9, 0x72, 0x84, 0x24, 0x55, 0x2a, 0x6f, 0xa7, 0x96, 0x33, 0x82, 0x07, 0x79, - 0x87, 0x55, 0x13, 0x3d, 0x87, 0xcd, 0xb9, 0xcd, 0x62, 0x2f, 0x99, 0xf9, 0x5e, 0xea, 0x1e, 0x6e, - 0x11, 0x6c, 0x5e, 0x4b, 0x36, 0x58, 0x08, 0x0d, 0xc5, 0xe7, 0x7d, 0xe8, 0xfb, 0xea, 0xa3, 0xa3, - 0x23, 0x51, 0xcb, 0x29, 0x16, 0x3e, 0x48, 0x18, 0x0d, 0x5b, 0xf2, 0x5b, 0x18, 0x8d, 0x7c, 0x6c, - 0x31, 0x1f, 0xa2, 0x22, 0x50, 0x6c, 0x16, 0x52, 0xf8, 0x47, 0xea, 0xc6, 0xb6, 0xe8, 0xbd, 0x70, - 0xf8, 0x47, 0x03, 0x6a, 0x8f, 0x8f, 0xbf, 0x32, 0x5e, 0xc1, 0x7a, 0xe9, 0xbd, 0x63, 0xa4, 0x63, - 0x65, 0xf1, 0xab, 0x6a, 0xf4, 0xd6, 0xb2, 0x63, 0xba, 0x38, 0xac, 0x09, 0xcc, 0xd2, 0xad, 0x42, - 0x63, 0x2e, 0xbe, 0xb3, 0x68, 0xcc, 0x65, 0x97, 0x91, 0x35, 0xe3, 0x13, 0x68, 0xaa, 0x37, 0x91, - 0xb1, 0x4d, 0xb2, 0x85, 0xc7, 0xd5, 0x68, 0xa7, 0xb4, 0xab, 0x15, 0x8f, 0x00, 0xb2, 0x97, 0x84, - 0x31, 0x24, 0xb1, 0xb9, 0xc7, 0xd4, 0x68, 0x6f, 0xc1, 0x89, 0x06, 0x39, 0x85, 0x8d, 0xf2, 0x53, - 0xc1, 0x28, 0xc5, 0xa1, 0x7c, 0xb1, 0x1f, 0xdd, 0x5a, 0x7a, 0x9e, 0x87, 0x2d, 0x3f, 0x18, 0x34, - 0xec, 0x92, 0xe7, 0x87, 0x86, 0x5d, 0xfa, 0xd2, 0x58, 0x33, 0xbe, 0x85, 0x41, 0xf1, 0xae, 0x6f, - 0xfc, 0x9f, 0x94, 0x16, 0x3e, 0x41, 0x46, 0x37, 0x97, 0x9c, 0x6a, 0xc0, 0x0f, 0x55, 0xe9, 0xe2, - 0x5d, 0x23, 0x8d, 0x72, 0xee, 0x21, 0x30, 0xda, 0x2e, 0x6e, 0x6a, 0xad, 0xfb, 0xd0, 0x54, 0x37, - 0x48, 0x9d, 0xb2, 0xc2, 0x85, 0x72, 0xd4, 0xcb, 0xef, 0x9a, 0x6b, 0xf7, 0x2b, 0x38, 0xa5, 0xda, - 0xcf, 0x18, 0x57, 0xf5, 0x9c, 0x37, 0x35, 0xa7, 0x22, 0x37, 0x85, 0xca, 0x59, 0x53, 0xfe, 0x17, - 0xf0, 0xe0, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x15, 0x52, 0xba, 0x18, 0x10, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x58, 0xdb, 0x72, 0xdc, 0x44, + 0x13, 0xf6, 0x9e, 0x77, 0x7b, 0x0f, 0xb6, 0xe5, 0xd8, 0x59, 0xef, 0xff, 0x87, 0x04, 0x11, 0x48, + 0x8a, 0x4a, 0xb9, 0x82, 0xc3, 0x21, 0x84, 0x0b, 0x08, 0x4e, 0x2a, 0x81, 0x4a, 0xc0, 0x95, 0xd8, + 0x54, 0x71, 0xc3, 0x96, 0x2c, 0x0d, 0x6b, 0xb1, 0x3a, 0x21, 0x8d, 0x7c, 0xb8, 0xe4, 0x96, 0x07, + 0xe2, 0x01, 0xa8, 0xe2, 0x9e, 0xe7, 0xe0, 0x29, 0x68, 0xcd, 0xb4, 0x46, 0x23, 0xed, 0xae, 0x03, + 0x17, 0xdc, 0xb8, 0x6a, 0x46, 0xdd, 0x5f, 0x7f, 0xfd, 0x75, 0xf7, 0xec, 0x8c, 0xa1, 0x67, 0x45, + 0xee, 0x5e, 0x14, 0x87, 0x3c, 0x34, 0x5a, 0xfc, 0x32, 0x62, 0x89, 0xf9, 0x02, 0x76, 0x0e, 0x62, + 0x66, 0x71, 0x76, 0x10, 0x06, 0xdc, 0x72, 0x03, 0x16, 0xbf, 0x62, 0x3f, 0xa7, 0x2c, 0xe1, 0x06, + 0x40, 0xdd, 0x75, 0xc6, 0xb5, 0x5b, 0xb5, 0xbb, 0x3d, 0x03, 0x17, 0x27, 0x69, 0xe0, 0x78, 0xec, + 0xd0, 0xe2, 0xa7, 0xe3, 0x7a, 0xbe, 0x67, 0x9f, 0x32, 0x7b, 0x1e, 0x85, 0x6e, 0xc0, 0xc7, 0x9d, + 0x6c, 0xcf, 0x3c, 0x86, 0xeb, 0x0b, 0x68, 0x49, 0x14, 0x06, 0x09, 0x33, 0xfa, 0xd0, 0x88, 0x08, + 0x6f, 0x68, 0x0c, 0xa1, 0x95, 0x70, 0xc7, 0x0d, 0x08, 0x6a, 0x04, 0x6d, 0x5c, 0x86, 0x29, 0x1f, + 0x37, 0xb4, 0x35, 0x8b, 0xe3, 0x71, 0x53, 0xc0, 0x3e, 0x84, 0xe1, 0x6b, 0x77, 0x16, 0x58, 0xde, + 0x32, 0x6e, 0x04, 0x5c, 0x20, 0x09, 0x4b, 0x81, 0x34, 0x34, 0x37, 0x60, 0x94, 0x7b, 0x4a, 0x1e, + 0xe6, 0x2f, 0x35, 0xd8, 0x7c, 0xec, 0x38, 0x87, 0x71, 0x68, 0xb3, 0x24, 0x59, 0x06, 0xb8, 0x01, + 0x5d, 0xce, 0x62, 0xdf, 0xcd, 0x50, 0x32, 0xd4, 0xae, 0xb1, 0x0b, 0xcd, 0x34, 0x61, 0xb1, 0xc0, + 0xec, 0xef, 0xf7, 0xf7, 0x84, 0x74, 0x7b, 0xc7, 0xb8, 0x65, 0x0c, 0xa0, 0x69, 0xc5, 0xb3, 0x04, + 0x89, 0x36, 0x24, 0x17, 0x16, 0x9c, 0x8d, 0x5b, 0xf9, 0xc2, 0x3e, 0x77, 0xc6, 0x6d, 0x9d, 0x65, + 0x87, 0xf2, 0x69, 0x0a, 0x67, 0xdc, 0x4c, 0x95, 0x26, 0xb8, 0x98, 0x51, 0x1e, 0x43, 0x63, 0x07, + 0x46, 0x96, 0xe3, 0xb8, 0xdc, 0x0d, 0x91, 0xc5, 0x33, 0xd7, 0x49, 0x30, 0x76, 0x03, 0xf3, 0x39, + 0x00, 0x43, 0x27, 0x4f, 0xda, 0x2a, 0x39, 0x6b, 0x15, 0x39, 0xeb, 0x15, 0x39, 0x85, 0xbc, 0x58, + 0xf3, 0xbc, 0x4a, 0xaa, 0x7e, 0xcb, 0x74, 0x78, 0xb7, 0x54, 0xe0, 0xba, 0xc8, 0x7d, 0x93, 0x72, + 0x2f, 0x3c, 0xcd, 0x09, 0x8c, 0x17, 0xd1, 0x48, 0xec, 0x07, 0x70, 0xfd, 0x09, 0xf3, 0xd8, 0x9b, + 0x22, 0xa1, 0x88, 0x81, 0xe5, 0x33, 0x49, 0x37, 0x03, 0x5c, 0x74, 0x22, 0xc0, 0x77, 0x60, 0xfb, + 0x85, 0x9b, 0xf0, 0x2b, 0xe1, 0xcc, 0xef, 0x01, 0x0a, 0x03, 0x05, 0xae, 0x42, 0xb1, 0x0b, 0x97, + 0x53, 0x61, 0x51, 0x73, 0x6e, 0x47, 0x42, 0x96, 0xae, 0xb1, 0x05, 0xfd, 0x34, 0x70, 0x2f, 0x5e, + 0x87, 0xf6, 0x9c, 0xf1, 0x44, 0xb4, 0x5e, 0x57, 0x48, 0x7b, 0xca, 0x3c, 0x0f, 0x6b, 0x8a, 0x4b, + 0xf3, 0x0b, 0xd8, 0xa9, 0xc6, 0xa7, 0x1a, 0xbc, 0x07, 0xfd, 0x42, 0xad, 0x04, 0xa3, 0x35, 0x96, + 0xcb, 0x35, 0x82, 0xc1, 0x6b, 0x8e, 0x6a, 0x11, 0x71, 0xf3, 0x16, 0x8c, 0xd4, 0xb0, 0x88, 0x0f, + 0xb2, 0x5c, 0x16, 0x4f, 0x13, 0x4a, 0x67, 0x0e, 0x1d, 0x2a, 0xb8, 0x3e, 0x44, 0xff, 0x4d, 0x9f, + 0x9a, 0x1e, 0xf4, 0x14, 0x9d, 0xd5, 0x35, 0xaa, 0x1c, 0x08, 0x72, 0x6a, 0xdf, 0x86, 0x5e, 0x24, + 0x79, 0x32, 0x19, 0xa7, 0xbf, 0x3f, 0x22, 0x0a, 0x39, 0xff, 0x22, 0xb5, 0x96, 0x88, 0x76, 0x07, + 0x3a, 0x2f, 0x2d, 0xfb, 0x14, 0x83, 0x65, 0xf8, 0x76, 0x44, 0x39, 0x0f, 0x33, 0x43, 0x9f, 0xf9, + 0x61, 0x7c, 0x29, 0xe2, 0x35, 0xcd, 0xef, 0xf0, 0x04, 0x90, 0xaa, 0x91, 0xdc, 0xb7, 0xb1, 0x39, + 0x73, 0x9e, 0xb9, 0xda, 0x1b, 0xb9, 0xda, 0x2a, 0x81, 0x9b, 0xd0, 0xf1, 0x25, 0x3e, 0xf5, 0x6f, + 0x4e, 0x88, 0xa2, 0x9a, 0x4f, 0x60, 0xe7, 0x38, 0x72, 0xde, 0x74, 0xfc, 0x15, 0xa7, 0x4a, 0x3d, + 0x67, 0x47, 0x69, 0xc8, 0x81, 0xda, 0x85, 0xeb, 0x0b, 0x28, 0xd4, 0xb0, 0xeb, 0x30, 0x7c, 0x7a, + 0xc6, 0xb0, 0x23, 0xf2, 0x7a, 0xff, 0x59, 0x83, 0x96, 0xd8, 0xc9, 0x32, 0xce, 0xc8, 0x50, 0x0c, + 0x19, 0x4f, 0x1b, 0x58, 0x85, 0x3f, 0xac, 0xa8, 0xdd, 0xd4, 0x0f, 0x94, 0x56, 0x85, 0x60, 0x47, + 0x38, 0x60, 0xde, 0x54, 0x8a, 0x71, 0xb7, 0x94, 0x77, 0x5e, 0x88, 0xb2, 0x7c, 0xbd, 0x15, 0xf2, + 0x95, 0x4f, 0x00, 0x58, 0x75, 0x02, 0xfc, 0x56, 0x83, 0xc1, 0x37, 0x8c, 0x9f, 0x87, 0xf1, 0x3c, + 0x2b, 0x52, 0x52, 0x19, 0x39, 0xec, 0xd3, 0xf8, 0x62, 0x7a, 0x72, 0xc9, 0xb1, 0x2d, 0x44, 0x35, + 0xb3, 0x7c, 0x70, 0xe7, 0xd0, 0x92, 0x83, 0xd6, 0x10, 0x7b, 0x9b, 0xd0, 0x7b, 0x75, 0x31, 0xc5, + 0x43, 0x2a, 0x8c, 0xe5, 0xec, 0x09, 0x33, 0xdc, 0x72, 0xe2, 0x30, 0x8a, 0x98, 0xcc, 0xb4, 0x99, + 0x81, 0x1d, 0xe5, 0x60, 0xed, 0xdc, 0x0a, 0x77, 0x22, 0x02, 0xeb, 0xe4, 0x60, 0x47, 0x0a, 0xac, + 0xab, 0x99, 0xe5, 0x60, 0x3d, 0xd1, 0x55, 0x3e, 0x74, 0x0f, 0xa2, 0xf4, 0x38, 0xb1, 0x66, 0x2c, + 0x9b, 0x7e, 0x1e, 0x72, 0xcb, 0x9b, 0xa6, 0xd9, 0x52, 0x50, 0x6f, 0x1a, 0xd7, 0x60, 0x10, 0xb1, + 0x18, 0xfb, 0x92, 0x76, 0xeb, 0x28, 0x54, 0xd3, 0xf8, 0x1f, 0x6c, 0x89, 0xe5, 0xd4, 0x0d, 0xa6, + 0x73, 0x16, 0x07, 0xcc, 0xf3, 0x43, 0x87, 0x51, 0x1e, 0xbb, 0xb0, 0xa9, 0x3e, 0x66, 0xc3, 0x28, + 0x3e, 0x89, 0x7c, 0xcc, 0x23, 0x18, 0x1d, 0x9d, 0xe2, 0x8f, 0x2f, 0xf7, 0xdc, 0x60, 0xf6, 0xc4, + 0xe2, 0x96, 0xb1, 0x8e, 0x75, 0x62, 0xb1, 0x1b, 0x3a, 0x09, 0x05, 0x44, 0x6f, 0x2e, 0x4d, 0x98, + 0x33, 0xcd, 0x3f, 0x49, 0xd1, 0xf0, 0x27, 0xa1, 0xf8, 0xc4, 0x5d, 0x9f, 0x02, 0x9a, 0x3f, 0x88, + 0x24, 0xa4, 0xf0, 0x26, 0xf4, 0x0a, 0xb2, 0x35, 0x51, 0xaf, 0xf5, 0xbc, 0x5e, 0x79, 0xa2, 0x7b, + 0xb0, 0xce, 0x15, 0x8b, 0x29, 0x76, 0xad, 0x45, 0xb3, 0xb1, 0x4d, 0x96, 0x65, 0x8e, 0xe6, 0xe7, + 0x00, 0x2f, 0xc5, 0x28, 0x0a, 0xc6, 0x78, 0x1e, 0xea, 0x02, 0xa1, 0xd0, 0xbe, 0x75, 0xa1, 0xd4, + 0xc9, 0xb6, 0x30, 0xa7, 0x1f, 0x2d, 0xd7, 0xb3, 0x03, 0x4e, 0x04, 0xff, 0xaa, 0x41, 0x5f, 0x22, + 0x48, 0x92, 0x08, 0x61, 0xe3, 0xf8, 0xe5, 0x10, 0xb7, 0x72, 0xc4, 0xf2, 0x2f, 0x8c, 0x16, 0x13, + 0xdb, 0x30, 0x39, 0xb7, 0x22, 0x8a, 0xd2, 0x58, 0x65, 0x76, 0x07, 0x06, 0xb2, 0x1a, 0x64, 0xd8, + 0x5c, 0x65, 0x78, 0x2f, 0xfb, 0xb9, 0x44, 0x26, 0xe2, 0xfc, 0xeb, 0xef, 0xdf, 0x28, 0x59, 0x08, + 0x8e, 0x7b, 0xe2, 0xef, 0xd3, 0x80, 0xc7, 0x97, 0x93, 0x7b, 0x00, 0xc5, 0x2a, 0x1b, 0xbb, 0x39, + 0xbb, 0xa4, 0xce, 0xc6, 0x4c, 0xce, 0x2c, 0x2f, 0xa5, 0xcc, 0x1f, 0xd5, 0x1f, 0xd6, 0xcc, 0xaf, + 0x61, 0xfd, 0x4b, 0x6f, 0xee, 0x86, 0x9a, 0x0b, 0x5a, 0xf9, 0xd6, 0x4f, 0x61, 0x4c, 0xf9, 0x66, + 0x4b, 0x37, 0xc0, 0xa5, 0x94, 0x0b, 0xe7, 0x3e, 0x8c, 0xe8, 0x04, 0x55, 0x78, 0xb2, 0x5f, 0x7e, + 0x6f, 0x00, 0x14, 0x60, 0xc6, 0x23, 0x98, 0xb8, 0xe1, 0x14, 0x5b, 0xea, 0xcc, 0xb5, 0x99, 0x1c, + 0x81, 0x69, 0xcc, 0xec, 0x34, 0x4e, 0xdc, 0x33, 0x46, 0x47, 0xe0, 0x0e, 0xe5, 0x52, 0xe5, 0xf0, + 0x11, 0x6c, 0x17, 0xbe, 0x8e, 0xe6, 0x56, 0xbf, 0xd2, 0xed, 0x01, 0x6c, 0xa1, 0x1b, 0x1e, 0x5c, + 0x69, 0xc9, 0xa9, 0x71, 0xa5, 0xd3, 0xa7, 0xb0, 0xab, 0xf1, 0xcc, 0x3a, 0x55, 0x73, 0x6d, 0x5e, + 0xe9, 0xfa, 0x31, 0xec, 0xa0, 0xeb, 0xb9, 0xe5, 0xf2, 0xaa, 0x5f, 0xeb, 0x1f, 0xf0, 0xf4, 0x59, + 0x3c, 0x2b, 0xf1, 0x6c, 0x5f, 0xe9, 0xf4, 0x01, 0x6c, 0xa2, 0x53, 0x25, 0x4e, 0xe7, 0x4d, 0x2e, + 0x09, 0xb3, 0x39, 0x9e, 0x2a, 0x9a, 0x4b, 0xf7, 0x2a, 0x17, 0xf3, 0x31, 0x0c, 0x9e, 0xa7, 0x33, + 0xc6, 0xbd, 0x13, 0xd5, 0xfd, 0xff, 0x76, 0x80, 0x7e, 0xad, 0x43, 0xff, 0x60, 0x16, 0x87, 0x69, + 0x54, 0x9a, 0x72, 0xd9, 0xc3, 0x0b, 0x53, 0x2e, 0x6d, 0xee, 0xc2, 0x40, 0xfe, 0x80, 0x92, 0x99, + 0x1c, 0x2e, 0x63, 0xb1, 0xd5, 0xb3, 0x8b, 0xcb, 0x49, 0xc6, 0x99, 0x0c, 0xcb, 0xe3, 0xa5, 0xb5, + 0xdf, 0x67, 0x30, 0x3c, 0x95, 0x89, 0x90, 0xa5, 0x2c, 0xe5, 0xed, 0x3c, 0x72, 0x41, 0x70, 0x4f, + 0x4f, 0x58, 0x0e, 0xd1, 0x73, 0xd8, 0x5c, 0xd8, 0x2c, 0xcf, 0x92, 0xa9, 0xcf, 0x52, 0x7f, 0x7f, + 0x8b, 0x60, 0x75, 0x2f, 0x31, 0x60, 0x11, 0xb4, 0x24, 0x9f, 0xf7, 0x61, 0x18, 0xc8, 0x1f, 0x1d, + 0xa5, 0x44, 0x43, 0x73, 0x2c, 0xfd, 0x20, 0xa1, 0x1a, 0xb6, 0xe0, 0xb7, 0x54, 0x0d, 0x5d, 0x5b, + 0xac, 0x47, 0xd6, 0x11, 0x68, 0xe6, 0x47, 0x24, 0xff, 0x44, 0xde, 0xd8, 0x96, 0xbd, 0x15, 0xf6, + 0xff, 0x68, 0x41, 0xe3, 0xf1, 0xe1, 0x57, 0xc6, 0x2b, 0x58, 0xaf, 0x3c, 0x7c, 0x8c, 0xfc, 0x58, + 0x59, 0xfe, 0xbc, 0x9a, 0xbc, 0xb5, 0xea, 0x33, 0x5d, 0x1c, 0xd6, 0x32, 0xcc, 0xca, 0xad, 0x42, + 0x61, 0x2e, 0xbf, 0xb3, 0x28, 0xcc, 0x55, 0x97, 0x91, 0x35, 0xe3, 0x13, 0x68, 0xcb, 0xf7, 0x90, + 0x71, 0x8d, 0x6c, 0x4b, 0x0f, 0xab, 0xc9, 0x76, 0x65, 0x57, 0x39, 0x1e, 0x00, 0x14, 0x0f, 0x0f, + 0x63, 0x4c, 0x66, 0x0b, 0x0f, 0xa9, 0xc9, 0xee, 0x92, 0x2f, 0x0a, 0xe4, 0x18, 0x36, 0xaa, 0x4f, + 0x05, 0xa3, 0xa2, 0x43, 0xf5, 0x62, 0x3f, 0xb9, 0xb9, 0xf2, 0xbb, 0x0e, 0x5b, 0x7d, 0x30, 0x28, + 0xd8, 0x15, 0xcf, 0x0f, 0x05, 0xbb, 0xf2, 0xa5, 0xb1, 0x66, 0x7c, 0x0b, 0xa3, 0xf2, 0x5d, 0xdf, + 0xf8, 0x3f, 0x39, 0x2d, 0x7d, 0x82, 0x4c, 0x6e, 0xac, 0xf8, 0xaa, 0x00, 0x3f, 0x94, 0xad, 0x8b, + 0x77, 0x8d, 0x5c, 0x65, 0xed, 0x21, 0x30, 0xb9, 0x56, 0xde, 0x54, 0x5e, 0xf7, 0xa1, 0x2d, 0x6f, + 0x90, 0xaa, 0x64, 0xa5, 0x0b, 0xe5, 0x64, 0xa0, 0xef, 0x9a, 0x6b, 0xf7, 0x6b, 0x78, 0x4a, 0x75, + 0x9f, 0x31, 0x2e, 0xfb, 0x59, 0x0f, 0xb5, 0xe0, 0x22, 0x36, 0x33, 0x97, 0x93, 0xb6, 0xf8, 0xa7, + 0xc0, 0x83, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x0f, 0x82, 0xdf, 0x21, 0x10, 0x00, 0x00, } diff --git a/api/grpc/types/api.proto b/api/grpc/types/api.proto index 641dfef..be0bc28 100644 --- a/api/grpc/types/api.proto +++ b/api/grpc/types/api.proto @@ -23,9 +23,9 @@ message CreateContainerRequest { message CreateContainerResponse { uint32 pid = 1; // PID of the containers main process - 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) + string stdin = 2; // path to the file where stdin will be read (optional) + string stdout = 3; // path to file where stdout will be written (optional) + string stderr = 4; // path to file where stderr will be written (optional) } message SignalRequest { @@ -44,10 +44,7 @@ message AddProcessRequest { repeated string args = 4; // Arguments for process, first is binary path itself repeated string env = 5; // List of environment variables for process string cwd = 6; // Workind directory of process - string stdin = 7; // path to the file where stdin will be read (optional) - 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) + string pid = 7; // Process ID }; message User { @@ -57,6 +54,9 @@ message User { } 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 { diff --git a/containerd-shim/example/config.json b/containerd-shim/example/config.json new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/exit b/containerd-shim/example/init/exit new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/pid b/containerd-shim/example/init/pid new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/process.json b/containerd-shim/example/init/process.json new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/resize b/containerd-shim/example/init/resize new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/stderr b/containerd-shim/example/init/stderr new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/stdin b/containerd-shim/example/init/stdin new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/init/stdout b/containerd-shim/example/init/stdout new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/exit b/containerd-shim/example/logger/exit new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/pid b/containerd-shim/example/logger/pid new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/process.json b/containerd-shim/example/logger/process.json new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/resize b/containerd-shim/example/logger/resize new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/stderr b/containerd-shim/example/logger/stderr new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/stdin b/containerd-shim/example/logger/stdin new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/example/logger/stdout b/containerd-shim/example/logger/stdout new file mode 100644 index 0000000..e69de29 diff --git a/containerd-shim/main.go b/containerd-shim/main.go index 0de23bc..7450525 100644 --- a/containerd-shim/main.go +++ b/containerd-shim/main.go @@ -1,43 +1,21 @@ package main import ( - "encoding/json" + "flag" "fmt" - "io" - "io/ioutil" "os" - "os/exec" "os/signal" - "path/filepath" - "strconv" "syscall" "github.com/Sirupsen/logrus" "github.com/docker/containerd/util" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/specs" ) -const ( - bufferSize = 2048 -) +var fexec bool -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 +func init() { + flag.BoolVar(&fexec, "exec", false, "exec a process instead of starting the init") + flag.Parse() } // 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 // to the state directory where the shim can locate fifos and other information. -// -// └── shim -// ├── control -// ├── stderr -// ├── stdin -// ├── stdout -// ├── pid -// └── exit 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 // or if runc exits before we hit the handler - signals := make(chan os.Signal, bufferSize) + signals := make(chan os.Signal, 2048) signal.Notify(signals) // set the shim as the subreaper for all orphaned processes created by the container if err := util.SetSubreaper(1); err != nil { logrus.WithField("error", err).Fatal("shim: set as subreaper") } // 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 { logrus.WithField("error", err).Fatal("shim: open exit pipe") } defer f.Close() - // open the fifos for use with the command - std, err := openContainerSTDIO(os.Args[1]) + p, err := newProcess(flag.Arg(0), flag.Arg(1), fexec) 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 - runcPid, err := startRunc(std, os.Args[2]) - if err != nil { - logrus.WithField("error", err).Fatal("shim: start runc") + if err := p.start(); err != nil { + logrus.WithField("error", err).Fatal("shim: start process") } var exitShim bool for s := range signals { @@ -92,22 +56,27 @@ func main() { } for _, e := range exits { // check to see if runc is one of the processes that has exited - if e.Pid == runcPid { + if e.Pid == p.pid() { exitShim = true - logrus.WithFields(logrus.Fields{"pid": e.Pid, "status": e.Status}).Info("shim: runc exited") - - if err := writeInt(filepath.Join(os.Args[1], "exitStatus"), e.Status); err != nil { - logrus.WithFields(logrus.Fields{"error": err, "status": e.Status}).Error("shim: write exit status") + logrus.WithFields(logrus.Fields{ + "pid": e.Pid, + "status": e.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 if exitShim { - if err := std.Close(); err != nil { + if err := p.Close(); err != nil { 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") } 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 { f, err := os.Create(path) if err != nil { diff --git a/containerd-shim/process.go b/containerd-shim/process.go new file mode 100644 index 0000000..cc7e592 --- /dev/null +++ b/containerd-shim/process.go @@ -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 +} diff --git a/ctr/container.go b/ctr/container.go index 48f56e1..3540bd5 100644 --- a/ctr/container.go +++ b/ctr/container.go @@ -145,7 +145,7 @@ var attachCommand = cli.Command{ io.Copy(stdin, os.Stdin) closer() }() - if err := waitForExit(c, id, closer); err != nil { + if err := waitForExit(c, id, "init", closer); err != nil { fatal(err.Error(), 1) } }, @@ -217,7 +217,7 @@ var startCommand = cli.Command{ io.Copy(stdin, os.Stdin) restoreAndCloseStdin() }() - if err := waitForExit(c, id, restoreAndCloseStdin); err != nil { + if err := waitForExit(c, id, "init", restoreAndCloseStdin); err != nil { fatal(err.Error(), 1) } } @@ -303,6 +303,10 @@ var execCommand = cli.Command{ Name: "id", Usage: "container id to add the process to", }, + cli.StringFlag{ + Name: "pid", + Usage: "process id for the new process", + }, cli.BoolFlag{ Name: "attach,a", Usage: "connect to the stdio of the container", @@ -330,58 +334,50 @@ var execCommand = cli.Command{ }, }, Action: func(context *cli.Context) { - panic("not implemented") - /* - p := &types.AddProcessRequest{ - Args: context.Args(), - Cwd: context.String("cwd"), - Terminal: context.Bool("tty"), - Id: context.String("id"), - Env: context.StringSlice("env"), - User: &types.User{ - Uid: uint32(context.Int("uid")), - Gid: uint32(context.Int("gid")), - }, - } - c := getClient(context) - events, err := c.Events(netcontext.Background(), &types.EventsRequest{}) - if err != nil { - fatal(err.Error(), 1) - } - if context.Bool("attach") { - if p.Terminal { - 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) + p := &types.AddProcessRequest{ + Pid: context.String("pid"), + Args: context.Args(), + Cwd: context.String("cwd"), + Terminal: context.Bool("tty"), + Id: context.String("id"), + Env: context.StringSlice("env"), + User: &types.User{ + Uid: uint32(context.Int("uid")), + Gid: uint32(context.Int("gid")), + }, + } + c := getClient(context) + resp, err := c.AddProcess(netcontext.Background(), p) + if err != nil { + fatal(err.Error(), 1) + } + if context.Bool("attach") { + if context.Bool("tty") { + s, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { fatal(err.Error(), 1) } - if context.Bool("attach") { - go func() { - io.Copy(stdin, os.Stdin) - if state != nil { - term.RestoreTerminal(os.Stdin.Fd(), state) - } - stdin.Close() - }() - for { - e, err := events.Recv() - if err != nil { - fatal(err.Error(), 1) - } - if e.Pid == r.Pid && e.Type == "exit" { - os.Exit(int(e.Status)) - } - } + state = s + } + if err := attachStdio(resp.Stdin, resp.Stdout, resp.Stderr); err != nil { + fatal(err.Error(), 1) + } + } + if context.Bool("attach") { + restoreAndCloseStdin := func() { + if state != nil { + term.RestoreTerminal(os.Stdin.Fd(), state) } - */ + 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{}) if err != nil { return err @@ -419,7 +415,7 @@ func waitForExit(c types.APIClient, id string, closer func()) error { events, _ = c.Events(netcontext.Background(), &types.EventsRequest{}) continue } - if e.Id == id && e.Type == "exit" && e.Pid == "init" { + if e.Id == id && e.Type == "exit" && e.Pid == pid { closer() os.Exit(int(e.Status)) } diff --git a/runtime/container.go b/runtime/container.go index 7c7f1ef..c7667f0 100644 --- a/runtime/container.go +++ b/runtime/container.go @@ -1,97 +1,17 @@ package runtime import ( - "io" + "encoding/json" + "io/ioutil" "os" - "time" + "os/exec" + "path/filepath" + "syscall" + "github.com/Sirupsen/logrus" "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 { // ID returns the container ID ID() string @@ -99,10 +19,10 @@ type Container interface { Path() string // Start starts the init process of the container 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() error - // Pid returns the container's init process id - // Pid() (int, error) // Processes returns all the containers processes that have been added Processes() ([]Process, error) // State returns the containers runtime state @@ -111,6 +31,7 @@ type Container interface { Resume() error // Pause pauses a running container Pause() error + RemoveProcess(string) error // Checkpoints returns all the checkpoints for a container // Checkpoints() ([]Checkpoint, error) // Checkpoint creates a new checkpoint @@ -124,3 +45,183 @@ type Container interface { // OOM signals the channel if the container received an OOM notification // 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 +} diff --git a/runtime/lib.go b/runtime/lib.go deleted file mode 100644 index f8b926c..0000000 --- a/runtime/lib.go +++ /dev/null @@ -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 -} diff --git a/runtime/process.go b/runtime/process.go index f094231..aeafc5a 100644 --- a/runtime/process.go +++ b/runtime/process.go @@ -1,6 +1,8 @@ package runtime import ( + "encoding/json" + "io" "io/ioutil" "os" "path/filepath" @@ -10,6 +12,31 @@ import ( "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) { p := &process{ root: root, @@ -17,6 +44,14 @@ func newProcess(root, id string, c *container, s specs.Process) (*process, error container: c, 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 for name, fd := range map[string]*string{ "stdin": &p.stdin, @@ -58,7 +93,7 @@ func loadProcess(root, id string, c *container, s specs.Process) (*process, erro } return nil, err } - return nil, ErrProcessExited + return p, nil } func getExitPipe(path string) (*os.File, error) { diff --git a/runtime/runtime.go b/runtime/runtime.go index d4a35a8..7c5949a 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -1,6 +1,9 @@ package runtime -import "errors" +import ( + "errors" + "time" +) var ( ErrNotChildProcess = errors.New("containerd: not a child process for container") @@ -14,3 +17,46 @@ var ( 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 +} diff --git a/supervisor/add_process.go b/supervisor/add_process.go index 3a07391..9a3f68e 100644 --- a/supervisor/add_process.go +++ b/supervisor/add_process.go @@ -1,5 +1,7 @@ package supervisor +import "time" + type AddProcessEvent struct { 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 // could be stopped and removed... func (h *AddProcessEvent) Handle(e *Event) error { - /* - start := time.Now() - ci, ok := h.s.containers[e.ID] - if !ok { - return ErrContainerNotFound - } - p, io, err := h.s.runtime.StartProcess(ci.container, *e.Process, e.Console) - if err != nil { - return err - } - if e.Pid, err = p.Pid(); err != nil { - return err - } - h.s.processes[e.Pid] = &containerInfo{ - container: ci.container, - } - l, err := h.s.copyIO(e.Stdin, e.Stdout, e.Stderr, io) - 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) - */ + start := time.Now() + ci, ok := h.s.containers[e.ID] + if !ok { + return ErrContainerNotFound + } + process, err := ci.container.Exec(e.Pid, *e.ProcessSpec) + if err != nil { + return err + } + if err := h.s.monitorProcess(process); err != nil { + return err + } + ExecProcessTimer.UpdateSince(start) + e.StartResponse <- StartResponse{ + Stdin: process.Stdin(), + Stdout: process.Stdout(), + Stderr: process.Stderr(), + } return nil } diff --git a/supervisor/delete.go b/supervisor/delete.go index 1888ab1..efccb56 100644 --- a/supervisor/delete.go +++ b/supervisor/delete.go @@ -17,11 +17,6 @@ func (h *DeleteEvent) Handle(e *Event) error { if err := h.deleteContainer(i.container); err != nil { 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{ Type: ExitEventType, ID: e.ID, diff --git a/supervisor/exit.go b/supervisor/exit.go index fecfed8..d1bf276 100644 --- a/supervisor/exit.go +++ b/supervisor/exit.go @@ -25,7 +25,9 @@ func (h *ExitEvent) Handle(e *Event) error { if proc.ID() != runtime.InitProcessID { ne := NewEvent(ExecExitEventType) ne.ID = proc.Container().ID() + ne.Pid = proc.ID() ne.Status = status + ne.Process = proc h.s.SendEvent(ne) return nil @@ -51,17 +53,11 @@ type ExecExitEvent struct { } func (h *ExecExitEvent) Handle(e *Event) error { + container := e.Process.Container() // exec process: we remove this process without notifying the main event loop - /* - info := h.s.processes[e.Pid] - if err := info.container.RemoveProcess(e.Pid); err != nil { - logrus.WithField("error", err).Error("containerd: find container for pid") - } - 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) - */ + if err := container.RemoveProcess(e.Pid); err != nil { + logrus.WithField("error", err).Error("containerd: find container for pid") + } + h.s.notifySubscribers(e) return nil } diff --git a/supervisor/io.go b/supervisor/io.go deleted file mode 100644 index fb43f07..0000000 --- a/supervisor/io.go +++ /dev/null @@ -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 -} diff --git a/supervisor/metrics.go b/supervisor/metrics.go index 80ca4ba..2e1b38a 100644 --- a/supervisor/metrics.go +++ b/supervisor/metrics.go @@ -11,6 +11,7 @@ var ( EventsCounter = metrics.NewCounter() ExecProcessTimer = metrics.NewTimer() ExitProcessTimer = metrics.NewTimer() + EpollFdCounter = metrics.NewCounter() ) func Metrics() map[string]interface{} { @@ -23,5 +24,6 @@ func Metrics() map[string]interface{} { "events": EventsCounter, "exec-process-time": ExecProcessTimer, "exit-process-time": ExitProcessTimer, + "epoll-fds": EpollFdCounter, } } diff --git a/supervisor/monitor.go b/supervisor/monitor.go index 6cd191d..3a3046b 100644 --- a/supervisor/monitor.go +++ b/supervisor/monitor.go @@ -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 { return err } + EpollFdCounter.Inc(1) m.processes[fd] = p return nil } @@ -75,6 +76,7 @@ func (m *Monitor) start() { }); err != nil { logrus.WithField("error", err).Fatal("containerd: epoll remove fd") } + EpollFdCounter.Dec(1) if err := proc.Close(); err != nil { logrus.WithField("error", err).Error("containerd: close process IO") } diff --git a/supervisor/signal.go b/supervisor/signal.go index 51df0ed..b5a7e4c 100644 --- a/supervisor/signal.go +++ b/supervisor/signal.go @@ -5,20 +5,18 @@ type SignalEvent struct { } func (h *SignalEvent) Handle(e *Event) error { - /* - i, ok := h.s.containers[e.ID] - if !ok { - return ErrContainerNotFound + i, ok := h.s.containers[e.ID] + if !ok { + 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 } diff --git a/supervisor/sort_test.go b/supervisor/sort_test.go new file mode 100644 index 0000000..1f21767 --- /dev/null +++ b/supervisor/sort_test.go @@ -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) + } +} diff --git a/supervisor/supervisor.go b/supervisor/supervisor.go index 652d1c6..f28ac9a 100644 --- a/supervisor/supervisor.go +++ b/supervisor/supervisor.go @@ -3,7 +3,7 @@ package supervisor import ( "io/ioutil" "os" - "path/filepath" + "sort" "sync" "time" @@ -76,7 +76,6 @@ func New(stateDir string, tasks chan *StartTask, oom bool) (*Supervisor, error) type containerInfo struct { container runtime.Container - copier *copier } type Supervisor struct { @@ -195,14 +194,6 @@ func (s *Supervisor) restore() error { id := d.Name() container, err := runtime.Load(s.stateDir, id) 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 } processes, err := container.Processes() @@ -214,11 +205,42 @@ func (s *Supervisor) restore() error { container: container, } logrus.WithField("id", id).Debug("containerd: container restored") + var exitedProcesses []runtime.Process for _, p := range processes { - if err := s.monitorProcess(p); err != nil { - return err + if _, err := p.ExitStatus(); err == nil { + 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 } + +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" +} diff --git a/supervisor/update.go b/supervisor/update.go index 7bc4292..6008ee1 100644 --- a/supervisor/update.go +++ b/supervisor/update.go @@ -27,17 +27,17 @@ func (h *UpdateEvent) Handle(e *Event) error { } } if e.Signal != nil { - /* - // signal the pid1/main process of the container - processes, err := container.Processes() - if err != nil { - return err + // signal the pid1/main process of the container + processes, err := container.Processes() + if err != nil { + return err + } + for _, p := range processes { + if p.ID() == runtime.InitProcessID { + return p.Signal(e.Signal) } - if len(processes) == 0 { - return ErrProcessNotFound - } - return processes[0].Signal(e.Signal) - */ + } + return ErrProcessNotFound } return nil } diff --git a/supervisor/worker.go b/supervisor/worker.go index 6759b69..80b4e1d 100644 --- a/supervisor/worker.go +++ b/supervisor/worker.go @@ -15,7 +15,6 @@ type Worker interface { type StartTask struct { Container runtime.Container Checkpoint string - IO *runtime.IO Stdin string Stdout string Stderr string diff --git a/version.go b/version.go index b741b19..f0eda81 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package containerd -const Version = "0.0.4" +const Version = "0.0.5"