Add grpc service to shim

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2017-01-19 14:16:50 -08:00
parent e6de7ea4b5
commit c08e0e610c
8 changed files with 402 additions and 229 deletions

View file

@ -51,6 +51,9 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
type CreateRequest struct {
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"`
Runtime string `protobuf:"bytes,3,opt,name=runtime,proto3" json:"runtime,omitempty"`
}
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
@ -126,8 +129,11 @@ func (this *CreateRequest) GoString() string {
if this == nil {
return "nil"
}
s := make([]string, 0, 4)
s := make([]string, 0, 7)
s = append(s, "&shim.CreateRequest{")
s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
s = append(s, "Bundle: "+fmt.Sprintf("%#v", this.Bundle)+",\n")
s = append(s, "Runtime: "+fmt.Sprintf("%#v", this.Runtime)+",\n")
s = append(s, "}")
return strings.Join(s, "")
}
@ -446,6 +452,24 @@ func (m *CreateRequest) MarshalTo(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.ID) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.ID)))
i += copy(dAtA[i:], m.ID)
}
if len(m.Bundle) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle)))
i += copy(dAtA[i:], m.Bundle)
}
if len(m.Runtime) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintShim(dAtA, i, uint64(len(m.Runtime)))
i += copy(dAtA[i:], m.Runtime)
}
return i, nil
}
@ -636,6 +660,18 @@ func encodeVarintShim(dAtA []byte, offset int, v uint64) int {
func (m *CreateRequest) Size() (n int) {
var l int
_ = l
l = len(m.ID)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
l = len(m.Bundle)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
l = len(m.Runtime)
if l > 0 {
n += 1 + l + sovShim(uint64(l))
}
return n
}
@ -718,6 +754,9 @@ func (this *CreateRequest) String() string {
return "nil"
}
s := strings.Join([]string{`&CreateRequest{`,
`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
`Bundle:` + fmt.Sprintf("%v", this.Bundle) + `,`,
`Runtime:` + fmt.Sprintf("%v", this.Runtime) + `,`,
`}`,
}, "")
return s
@ -828,6 +867,93 @@ func (m *CreateRequest) Unmarshal(dAtA []byte) error {
return fmt.Errorf("proto: CreateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Bundle", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Bundle = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Runtime", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowShim
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthShim
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Runtime = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipShim(dAtA[iNdEx:])
@ -1431,30 +1557,32 @@ var (
func init() { proto.RegisterFile("shim.proto", fileDescriptorShim) }
var fileDescriptorShim = []byte{
// 385 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x51, 0xbd, 0x6e, 0xf2, 0x40,
0x10, 0xc4, 0xe6, 0xc3, 0xd2, 0xb7, 0x60, 0xf8, 0x74, 0x42, 0x88, 0xcf, 0x10, 0x83, 0x5c, 0xa5,
0x32, 0x22, 0x69, 0x52, 0x44, 0x8a, 0x44, 0xa0, 0x48, 0x87, 0xec, 0x07, 0x88, 0x0c, 0xde, 0xd8,
0x27, 0x01, 0xe7, 0xd8, 0x07, 0x81, 0x2e, 0x8f, 0x47, 0x99, 0x22, 0x45, 0xaa, 0x28, 0xf8, 0x09,
0xf2, 0x08, 0x91, 0xff, 0x04, 0x98, 0xd0, 0xed, 0xce, 0xce, 0x8d, 0xe6, 0x66, 0x00, 0x02, 0x97,
0xce, 0x75, 0xcf, 0x67, 0x9c, 0x11, 0x79, 0xca, 0x16, 0xdc, 0xa2, 0x0b, 0xf4, 0x6d, 0x7d, 0xd5,
0x57, 0x5a, 0x0e, 0x63, 0xce, 0x0c, 0x7b, 0xf1, 0x71, 0xb2, 0x7c, 0xea, 0xe1, 0xdc, 0xe3, 0x9b,
0x84, 0xab, 0xd4, 0x1d, 0xe6, 0xb0, 0x78, 0xec, 0x45, 0x53, 0x82, 0x6a, 0x35, 0x90, 0xef, 0x7d,
0xb4, 0x38, 0x1a, 0xf8, 0xbc, 0xc4, 0x80, 0x6b, 0x1a, 0x54, 0x33, 0x20, 0xf0, 0xd8, 0x22, 0x40,
0xf2, 0x0f, 0x8a, 0x1e, 0xb5, 0x9b, 0x42, 0x57, 0xb8, 0x94, 0x8d, 0x68, 0xd4, 0xaa, 0x50, 0x31,
0xb9, 0xe5, 0xf3, 0xec, 0x4d, 0x0d, 0xe4, 0x21, 0xce, 0x70, 0x2f, 0xd2, 0x87, 0x6a, 0x06, 0xa4,
0x22, 0x1d, 0x28, 0xe3, 0x9a, 0xf2, 0xc7, 0x80, 0x5b, 0x7c, 0x19, 0xa4, 0x62, 0x10, 0x41, 0x66,
0x8c, 0x68, 0x32, 0x94, 0x47, 0x6b, 0x9c, 0x66, 0x0a, 0x5d, 0xa8, 0x24, 0xeb, 0x59, 0x13, 0x06,
0xc0, 0x98, 0x6f, 0x52, 0x3e, 0x69, 0x80, 0x98, 0x9e, 0xff, 0x0e, 0xa4, 0xf0, 0xb3, 0x23, 0x3e,
0x0c, 0x0d, 0x91, 0xda, 0xa4, 0x0e, 0xa5, 0x17, 0x6a, 0x73, 0xb7, 0x29, 0xc6, 0x2f, 0x93, 0x85,
0x34, 0x40, 0x72, 0x91, 0x3a, 0x2e, 0x6f, 0x16, 0x63, 0x38, 0xdd, 0xae, 0xde, 0x45, 0x28, 0x9b,
0x2e, 0x9d, 0x9b, 0xe8, 0xaf, 0xe8, 0x14, 0xc9, 0x08, 0xa4, 0x24, 0x0c, 0xd2, 0xd6, 0x8f, 0xa2,
0xd6, 0x8f, 0x42, 0x53, 0x2e, 0xce, 0x5c, 0x53, 0xf3, 0xb7, 0x50, 0x8a, 0xf3, 0x22, 0xad, 0x1c,
0xef, 0x30, 0x45, 0xa5, 0xa1, 0x27, 0xf5, 0xe9, 0x59, 0x7d, 0xfa, 0x28, 0xaa, 0x2f, 0x32, 0x91,
0x84, 0x79, 0x62, 0xe2, 0x28, 0xf4, 0x13, 0x13, 0xb9, 0x06, 0xee, 0xe0, 0x4f, 0x94, 0x28, 0x51,
0x72, 0xb4, 0x83, 0xd4, 0x95, 0xd6, 0xaf, 0xb7, 0x54, 0xe0, 0x06, 0x8a, 0x63, 0xbe, 0x21, 0xff,
0x73, 0x9c, 0x7d, 0x09, 0xe7, 0x7e, 0x30, 0x68, 0x6f, 0x77, 0x6a, 0xe1, 0x63, 0xa7, 0x16, 0xbe,
0x77, 0xaa, 0xf0, 0x1a, 0xaa, 0xc2, 0x36, 0x54, 0x85, 0xb7, 0x50, 0x15, 0xbe, 0x42, 0x55, 0x98,
0x48, 0x31, 0xfb, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x9a, 0x8d, 0xf1, 0xd9, 0x02, 0x00,
0x00,
// 419 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x92, 0xbf, 0x8e, 0xd3, 0x40,
0x10, 0xc6, 0xcf, 0x0e, 0x67, 0xc4, 0xe4, 0x1c, 0xd0, 0xea, 0x14, 0x19, 0xe7, 0xf0, 0x9d, 0x5c,
0x51, 0x39, 0x3a, 0x68, 0x28, 0x90, 0x90, 0x42, 0x52, 0xd0, 0x45, 0x76, 0x45, 0x85, 0x9c, 0x78,
0xb0, 0x57, 0x8a, 0xbd, 0xc6, 0x5e, 0x87, 0xa4, 0xe3, 0xf1, 0x52, 0x52, 0x50, 0x50, 0x21, 0xe2,
0x27, 0xe0, 0x11, 0xd0, 0xae, 0xd7, 0x90, 0x38, 0x44, 0x74, 0x3b, 0x7f, 0xf4, 0xed, 0x37, 0xbf,
0x19, 0x80, 0x32, 0xa1, 0xa9, 0x97, 0x17, 0x8c, 0x33, 0x62, 0x2e, 0x59, 0xc6, 0x43, 0x9a, 0x61,
0x11, 0x79, 0xeb, 0x7b, 0x7b, 0x14, 0x33, 0x16, 0xaf, 0x70, 0x2c, 0x8b, 0x8b, 0xea, 0xe3, 0x18,
0xd3, 0x9c, 0x6f, 0x9b, 0x5e, 0xfb, 0x3a, 0x66, 0x31, 0x93, 0xcf, 0xb1, 0x78, 0x35, 0x59, 0xf7,
0x3d, 0x98, 0x6f, 0x0b, 0x0c, 0x39, 0xfa, 0xf8, 0xa9, 0xc2, 0x92, 0x93, 0x21, 0xe8, 0x34, 0xb2,
0xb4, 0x3b, 0xed, 0xf9, 0xa3, 0x89, 0x51, 0xff, 0xb8, 0xd5, 0xdf, 0x4d, 0x7d, 0x9d, 0x46, 0x64,
0x08, 0xc6, 0xa2, 0xca, 0xa2, 0x15, 0x5a, 0xba, 0xa8, 0xf9, 0x2a, 0x22, 0x16, 0x3c, 0x2c, 0xaa,
0x8c, 0xd3, 0x14, 0xad, 0x9e, 0x2c, 0xb4, 0xa1, 0xeb, 0xc2, 0xa0, 0x95, 0x2e, 0x73, 0x96, 0x95,
0x48, 0x9e, 0x40, 0x2f, 0x57, 0xe2, 0xa6, 0x2f, 0x9e, 0xee, 0x00, 0xae, 0x02, 0x1e, 0x16, 0x5c,
0xfd, 0xee, 0x3e, 0x06, 0x73, 0x8a, 0x2b, 0xfc, 0x63, 0xc7, 0xbd, 0x87, 0x41, 0x9b, 0x50, 0x22,
0xb7, 0xd0, 0xc7, 0x0d, 0xe5, 0x1f, 0x4a, 0x1e, 0xf2, 0xaa, 0x54, 0x62, 0x20, 0x52, 0x81, 0xcc,
0xb8, 0x26, 0xf4, 0x67, 0x1b, 0x5c, 0xb6, 0x0a, 0x77, 0x70, 0xd5, 0x84, 0x67, 0x4d, 0xf8, 0x00,
0x73, 0xbe, 0xfd, 0x1f, 0x80, 0x6b, 0xb8, 0xfc, 0x4c, 0x23, 0x9e, 0xc8, 0xf9, 0x4d, 0xbf, 0x09,
0x04, 0x96, 0x04, 0x69, 0x9c, 0x70, 0x39, 0xbd, 0xe9, 0xab, 0xe8, 0xc5, 0x37, 0x1d, 0xfa, 0x41,
0x42, 0xd3, 0x00, 0x8b, 0x35, 0x5d, 0x22, 0x99, 0x81, 0xd1, 0xc0, 0x20, 0x37, 0xde, 0xd1, 0xd2,
0xbc, 0x23, 0xfc, 0xf6, 0xb3, 0x33, 0x55, 0x65, 0xfe, 0x35, 0x5c, 0x4a, 0x5e, 0x64, 0xd4, 0xe9,
0x3b, 0xa4, 0x68, 0x0f, 0xbd, 0xe6, 0x10, 0xbc, 0xf6, 0x10, 0xbc, 0x99, 0x38, 0x04, 0x61, 0xa2,
0x81, 0x79, 0x62, 0xe2, 0x08, 0xfa, 0x89, 0x89, 0xce, 0x06, 0xde, 0xc0, 0x03, 0x41, 0x94, 0xd8,
0x9d, 0xb6, 0x03, 0xea, 0xf6, 0xe8, 0x9f, 0x35, 0x25, 0xf0, 0x0a, 0x7a, 0x73, 0xbe, 0x25, 0x4f,
0x3b, 0x3d, 0x7f, 0x97, 0x70, 0x6e, 0x82, 0xc9, 0xcd, 0x6e, 0xef, 0x5c, 0x7c, 0xdf, 0x3b, 0x17,
0xbf, 0xf6, 0x8e, 0xf6, 0xa5, 0x76, 0xb4, 0x5d, 0xed, 0x68, 0x5f, 0x6b, 0x47, 0xfb, 0x59, 0x3b,
0xda, 0xc2, 0x90, 0xdd, 0x2f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x98, 0x18, 0x12, 0xde, 0x23,
0x03, 0x00, 0x00,
}

View file

@ -14,7 +14,9 @@ service ShimService {
}
message CreateRequest {
string id = 1 [(gogoproto.customname) = "ID"];
string bundle = 2;
string runtime = 3;
}
message CreateResponse {

View file

@ -1,210 +1,104 @@
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"path/filepath"
"runtime"
"syscall"
"google.golang.org/grpc"
"github.com/docker/containerd"
"github.com/docker/containerd/api/shim"
"github.com/docker/containerd/sys"
"github.com/docker/docker/pkg/term"
"github.com/docker/containerd/utils"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
func writeMessage(f *os.File, level string, err error) {
fmt.Fprintf(f, `{"level": "%s","msg": "%s"}`, level, err)
f.Sync()
}
const usage = `
__ _ __ __ _
_________ ____ / /_____ _(_)___ ___ _________/ / _____/ /_ (_)___ ___
/ ___/ __ \/ __ \/ __/ __ ` + "`" + `/ / __ \/ _ \/ ___/ __ /_____/ ___/ __ \/ / __ ` + "`" + `__ \
/ /__/ /_/ / / / / /_/ /_/ / / / / / __/ / / /_/ /_____(__ ) / / / / / / / / /
\___/\____/_/ /_/\__/\__,_/_/_/ /_/\___/_/ \__,_/ /____/_/ /_/_/_/ /_/ /_/
shim for container lifecycle and reconnection
`
type controlMessage struct {
Type int
Width int
Height int
}
// containerd-shim is a small shim that sits in front of a runtime implementation
// that allows it to be reparented to init and handle reattach from the caller.
//
// the cwd of the shim should be the path to the state directory where the shim
// can locate fifos and other information.
// Arg0: id of the container
// Arg1: bundle path
// Arg2: runtime binary
func main() {
flag.Parse()
cwd, err := os.Getwd()
if err != nil {
panic(err)
app := cli.NewApp()
app.Name = "containerd-shim"
app.Version = containerd.Version
app.Usage = usage
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "debug",
Usage: "enable debug output in logs",
},
}
f, err := os.OpenFile(filepath.Join(cwd, "shim-log.json"), os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
if err != nil {
panic(err)
}
if err := start(f); err != nil {
// this means that the runtime failed starting the container and will have the
// proper error messages in the runtime log so we should to treat this as a
// shim failure because the sim executed properly
if err == errRuntime {
f.Close()
return
app.Before = func(context *cli.Context) error {
if context.GlobalBool("debug") {
logrus.SetLevel(logrus.DebugLevel)
}
// log the error instead of writing to stderr because the shim will have
// /dev/null as it's stdio because it is supposed to be reparented to system
// init and will not have anyone to read from it
writeMessage(f, "error", err)
f.Close()
return nil
}
app.Action = func(context *cli.Context) error {
// start handling signals as soon as possible so that things are properly reaped
// or if runtime exits before we hit the handler
signals, err := setupSignals()
if err != nil {
return err
}
var (
server = grpc.NewServer()
sv = &service{}
)
shim.RegisterShimServiceServer(server, sv)
l, err := utils.CreateUnixSocket("shim.sock")
if err != nil {
return err
}
go func() {
defer l.Close()
if err := server.Serve(l); err != nil {
l.Close()
logrus.WithError(err).Fatal("containerd-shim: GRPC server failure")
}
}()
for s := range signals {
switch s {
case syscall.SIGCHLD:
exits, err := utils.Reap(false)
if err != nil {
logrus.WithError(err).Error("reap exit status")
}
for _, e := range exits {
if err := sv.processExited(e); err != nil {
return err
}
}
case syscall.SIGTERM, syscall.SIGINT:
server.GracefulStop()
return nil
}
}
return nil
}
if err := app.Run(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "containerd-shim: %s\n", err)
os.Exit(1)
}
}
func start(log *os.File) error {
// start handling signals as soon as possible so that things are properly reaped
// or if runtime exits before we hit the handler
// setupSignals creates a new signal handler for all signals and sets the shim as a
// sub-reaper so that the container processes are reparented
func setupSignals() (chan os.Signal, error) {
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 := sys.SetSubreaper(1); err != nil {
return err
return nil, err
}
// open the exit pipe
f, err := os.OpenFile("exit", syscall.O_WRONLY, 0)
if err != nil {
return err
}
defer f.Close()
control, err := os.OpenFile("control", syscall.O_RDWR, 0)
if err != nil {
return err
}
defer control.Close()
p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2))
if err != nil {
return err
}
defer func() {
if err := p.Close(); err != nil {
writeMessage(log, "warn", err)
}
}()
if err := p.create(); err != nil {
p.delete()
return err
}
msgC := make(chan controlMessage, 32)
go func() {
for {
var m controlMessage
if _, err := fmt.Fscanf(control, "%d %d %d\n", &m.Type, &m.Width, &m.Height); err != nil {
continue
}
msgC <- m
}
}()
if runtime.GOOS == "solaris" {
return nil
}
var exitShim bool
for !exitShim {
select {
case s := <-signals:
switch s {
case syscall.SIGCHLD:
exits, _ := Reap(false)
for _, e := range exits {
// check to see if runtime is one of the processes that has exited
if e.Pid == p.pid() {
exitShim = true
writeInt("exitStatus", e.Status)
}
}
}
case msg := <-msgC:
switch msg.Type {
case 0:
// close stdin
if p.stdinCloser != nil {
p.stdinCloser.Close()
}
case 1:
if p.console == nil {
continue
}
ws := term.Winsize{
Width: uint16(msg.Width),
Height: uint16(msg.Height),
}
term.SetWinsize(p.console.Fd(), &ws)
}
}
}
// runtime has exited so the shim can also exit
// kill all processes in the container incase it was not running in
// its own PID namespace
p.killAll()
// wait for all the processes and IO to finish
p.Wait()
// delete the container from the runtime
p.delete()
// the close of the exit fifo will happen when the shim exits
return nil
}
func writeInt(path string, i int) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
_, err = fmt.Fprintf(f, "%d", i)
return err
}
// Exit is the wait4 information from an exited process
type Exit struct {
Pid int
Status int
}
// Reap reaps all child processes for the calling process and returns their
// exit information
func Reap(wait bool) (exits []Exit, err error) {
var (
ws syscall.WaitStatus
rus syscall.Rusage
)
flag := syscall.WNOHANG
if wait {
flag = 0
}
for {
pid, err := syscall.Wait4(-1, &ws, flag, &rus)
if err != nil {
if err == syscall.ECHILD {
return exits, nil
}
return exits, err
}
if pid <= 0 {
return exits, nil
}
exits = append(exits, Exit{
Pid: pid,
Status: exitStatus(ws),
})
}
}
const exitSignalOffset = 128
// exitStatus returns the correct exit status for a process based on if it
// was signaled or exited cleanly
func exitStatus(status syscall.WaitStatus) int {
if status.Signaled() {
return exitSignalOffset + int(status.Signal())
}
return status.ExitStatus()
return signals, nil
}

View file

@ -64,6 +64,7 @@ type process struct {
consolePath string
state *processState
runtime string
exitStatus int
}
func newProcess(id, bundle, runtimeName string) (*process, error) {
@ -273,10 +274,25 @@ func (p *process) initializeIO(rootuid int) (i *IO, err error) {
}
return i, nil
}
func (p *process) Close() error {
return p.stdio.Close()
}
func (p *process) start() error {
cmd := exec.Command(p.runtime, append(p.state.RuntimeArgs, "start", p.id)...)
cmd.SysProcAttr = setPDeathSig()
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("%s: %v", out, err)
}
return nil
}
func (p *process) setExited(status int) {
p.exitStatus = status
}
type stdio struct {
stdin *os.File
stdout *os.File

View file

@ -0,0 +1,72 @@
package main
import (
"github.com/docker/containerd/api/shim"
"github.com/docker/containerd/utils"
"github.com/docker/docker/pkg/term"
google_protobuf "github.com/golang/protobuf/ptypes/empty"
"golang.org/x/net/context"
)
type service struct {
init *process
}
func (s *service) Create(ctx context.Context, r *shim.CreateRequest) (*shim.CreateResponse, error) {
process, err := newProcess(r.ID, r.Bundle, r.Runtime)
if err != nil {
return nil, err
}
s.init = process
if err := process.create(); err != nil {
return nil, err
}
return &shim.CreateResponse{
Pid: uint32(process.pid()),
}, nil
}
func (s *service) Start(ctx context.Context, r *shim.StartRequest) (*google_protobuf.Empty, error) {
err := s.init.start()
return nil, err
}
func (s *service) Delete(ctx context.Context, r *shim.DeleteRequest) (*shim.DeleteResponse, error) {
// TODO: error when container has not stopped
err := s.init.killAll()
s.init.Wait()
if derr := s.init.delete(); err == nil {
err = derr
}
if cerr := s.init.Close(); err == nil {
err = cerr
}
return &shim.DeleteResponse{
ExitStatus: uint32(s.init.exitStatus),
}, err
}
func (s *service) Exec(ctx context.Context, r *shim.ExecRequest) (*shim.ExecResponse, error) {
return nil, nil
}
func (s *service) Pty(ctx context.Context, r *shim.PtyRequest) (*google_protobuf.Empty, error) {
if s.init.console == nil {
return nil, nil
}
ws := term.Winsize{
Width: uint16(r.Width),
Height: uint16(r.Height),
}
if err := term.SetWinsize(s.init.console.Fd(), &ws); err != nil {
return nil, err
}
return nil, nil
}
func (s *service) processExited(e utils.Exit) error {
if s.init.pid() == e.Pid {
s.init.setExited(e.Status)
}
return nil
}

View file

@ -23,6 +23,7 @@ import (
"github.com/docker/containerd/execution"
"github.com/docker/containerd/execution/executors/shim"
"github.com/docker/containerd/log"
"github.com/docker/containerd/utils"
metrics "github.com/docker/go-metrics"
"github.com/urfave/cli"
@ -30,11 +31,7 @@ import (
stand "github.com/nats-io/nats-streaming-server/server"
)
func main() {
app := cli.NewApp()
app.Name = "containerd"
app.Version = containerd.Version
app.Usage = `
const usage = `
__ _ __
_________ ____ / /_____ _(_)___ ___ _________/ /
/ ___/ __ \/ __ \/ __/ __ ` + "`" + `/ / __ \/ _ \/ ___/ __ /
@ -43,6 +40,12 @@ func main() {
high performance container runtime
`
func main() {
app := cli.NewApp()
app.Name = "containerd"
app.Version = containerd.Version
app.Usage = usage
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "debug",
@ -98,7 +101,7 @@ high performance container runtime
if path == "" {
return fmt.Errorf("--socket path cannot be empty")
}
l, err := createUnixSocket(path)
l, err := utils.CreateUnixSocket(path)
if err != nil {
return err
}
@ -171,16 +174,6 @@ high performance container runtime
}
}
func createUnixSocket(path string) (net.Listener, error) {
if err := os.MkdirAll(filepath.Dir(path), 0660); err != nil {
return nil, err
}
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
return nil, err
}
return net.Listen("unix", path)
}
func serveMetrics(address string) {
m := http.NewServeMux()
m.Handle("/metrics", metrics.Handler())

49
utils/reaper.go Normal file
View file

@ -0,0 +1,49 @@
package utils
import "syscall"
// Exit is the wait4 information from an exited process
type Exit struct {
Pid int
Status int
}
// Reap reaps all child processes for the calling process and returns their
// exit information
func Reap(wait bool) (exits []Exit, err error) {
var (
ws syscall.WaitStatus
rus syscall.Rusage
)
flag := syscall.WNOHANG
if wait {
flag = 0
}
for {
pid, err := syscall.Wait4(-1, &ws, flag, &rus)
if err != nil {
if err == syscall.ECHILD {
return exits, nil
}
return exits, err
}
if pid <= 0 {
return exits, nil
}
exits = append(exits, Exit{
Pid: pid,
Status: ExitStatus(ws),
})
}
}
const exitSignalOffset = 128
// ExitStatus returns the correct exit status for a process based on if it
// was signaled or exited cleanly
func ExitStatus(status syscall.WaitStatus) int {
if status.Signaled() {
return exitSignalOffset + int(status.Signal())
}
return status.ExitStatus()
}

19
utils/socket.go Normal file
View file

@ -0,0 +1,19 @@
package utils
import (
"net"
"os"
"path/filepath"
"syscall"
)
// CreateUnixSocket creates a unix socket and returns the listener
func CreateUnixSocket(path string) (net.Listener, error) {
if err := os.MkdirAll(filepath.Dir(path), 0660); err != nil {
return nil, err
}
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
return nil, err
}
return net.Listen("unix", path)
}