github.com/georgethebeatle/containerd@v0.2.5/containerd-shim/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "os/signal" 8 "path/filepath" 9 "syscall" 10 11 "github.com/docker/containerd/osutils" 12 "github.com/docker/docker/pkg/term" 13 ) 14 15 func writeMessage(f *os.File, level string, err error) { 16 fmt.Fprintf(f, `{"level": "%s","msg": "%s"}`, level, err) 17 } 18 19 type controlMessage struct { 20 Type int 21 Width int 22 Height int 23 } 24 25 // containerd-shim is a small shim that sits in front of a runtime implementation 26 // that allows it to be repartented to init and handle reattach from the caller. 27 // 28 // the cwd of the shim should be the path to the state directory where the shim 29 // can locate fifos and other information. 30 // Arg0: id of the container 31 // Arg1: bundle path 32 // Arg2: runtime binary 33 func main() { 34 flag.Parse() 35 cwd, err := os.Getwd() 36 if err != nil { 37 panic(err) 38 } 39 f, err := os.OpenFile(filepath.Join(cwd, "shim-log.json"), os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666) 40 if err != nil { 41 panic(err) 42 } 43 if err := start(f); err != nil { 44 // this means that the runtime failed starting the container and will have the 45 // proper error messages in the runtime log so we should to treat this as a 46 // shim failure because the sim executed properly 47 if err == errRuntime { 48 f.Close() 49 return 50 } 51 // log the error instead of writing to stderr because the shim will have 52 // /dev/null as it's stdio because it is supposed to be reparented to system 53 // init and will not have anyone to read from it 54 writeMessage(f, "error", err) 55 f.Close() 56 os.Exit(1) 57 } 58 } 59 60 func start(log *os.File) error { 61 // start handling signals as soon as possible so that things are properly reaped 62 // or if runtime exits before we hit the handler 63 signals := make(chan os.Signal, 2048) 64 signal.Notify(signals) 65 // set the shim as the subreaper for all orphaned processes created by the container 66 if err := osutils.SetSubreaper(1); err != nil { 67 return err 68 } 69 // open the exit pipe 70 f, err := os.OpenFile("exit", syscall.O_WRONLY, 0) 71 if err != nil { 72 return err 73 } 74 defer f.Close() 75 control, err := os.OpenFile("control", syscall.O_RDWR, 0) 76 if err != nil { 77 return err 78 } 79 defer control.Close() 80 p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2)) 81 if err != nil { 82 return err 83 } 84 defer func() { 85 if err := p.Close(); err != nil { 86 writeMessage(log, "warn", err) 87 } 88 }() 89 if err := p.create(); err != nil { 90 p.delete() 91 return err 92 } 93 msgC := make(chan controlMessage, 32) 94 go func() { 95 for { 96 var m controlMessage 97 if _, err := fmt.Fscanf(control, "%d %d %d\n", &m.Type, &m.Width, &m.Height); err != nil { 98 continue 99 } 100 msgC <- m 101 } 102 }() 103 var exitShim bool 104 for { 105 select { 106 case s := <-signals: 107 switch s { 108 case syscall.SIGCHLD: 109 exits, _ := osutils.Reap(false) 110 for _, e := range exits { 111 // check to see if runtime is one of the processes that has exited 112 if e.Pid == p.pid() { 113 exitShim = true 114 writeInt("exitStatus", e.Status) 115 } 116 } 117 } 118 // runtime has exited so the shim can also exit 119 if exitShim { 120 // Let containerd take care of calling the runtime 121 // delete. 122 // This is needed to be done first in order to ensure 123 // that the call to Reap does not block until all 124 // children of the container have died if init was not 125 // started in its own PID namespace. 126 f.Close() 127 p.Wait() 128 return nil 129 } 130 case msg := <-msgC: 131 switch msg.Type { 132 case 0: 133 // close stdin 134 if p.stdinCloser != nil { 135 p.stdinCloser.Close() 136 } 137 case 1: 138 if p.console == nil { 139 continue 140 } 141 ws := term.Winsize{ 142 Width: uint16(msg.Width), 143 Height: uint16(msg.Height), 144 } 145 term.SetWinsize(p.console.Fd(), &ws) 146 } 147 } 148 } 149 return nil 150 } 151 152 func writeInt(path string, i int) error { 153 f, err := os.Create(path) 154 if err != nil { 155 return err 156 } 157 defer f.Close() 158 _, err = fmt.Fprintf(f, "%d", i) 159 return err 160 }