containerd/linux/shim/init.go

166 lines
3.5 KiB
Go

package shim
import (
"context"
"io"
"os"
"path/filepath"
"sync"
"syscall"
"github.com/containerd/containerd"
shimapi "github.com/containerd/containerd/api/services/shim"
"github.com/crosbymichael/console"
runc "github.com/crosbymichael/go-runc"
"github.com/tonistiigi/fifo"
)
type initProcess struct {
sync.WaitGroup
id string
bundle string
console console.Console
io runc.IO
runc *runc.Runc
status int
pid int
closers []io.Closer
}
func newInitProcess(context context.Context, path string, r *shimapi.CreateRequest) (*initProcess, error) {
for _, rm := range r.Rootfs {
m := &containerd.Mount{
Type: rm.Type,
Source: rm.Source,
Options: rm.Options,
}
if err := m.Mount(filepath.Join(path, "rootfs")); err != nil {
return nil, err
}
}
runtime := &runc.Runc{
Command: r.Runtime,
Log: filepath.Join(path, "log.json"),
LogFormat: runc.JSON,
PdeathSignal: syscall.SIGKILL,
}
p := &initProcess{
id: r.ID,
bundle: r.Bundle,
runc: runtime,
}
var (
err error
socket *runc.ConsoleSocket
io runc.IO
)
if r.Terminal {
if socket, err = runc.NewConsoleSocket(filepath.Join(path, "pty.sock")); err != nil {
return nil, err
}
defer os.Remove(socket.Path())
} else {
// TODO: get uid/gid
if io, err = runc.NewPipeIO(0, 0); err != nil {
return nil, err
}
p.io = io
}
opts := &runc.CreateOpts{
PidFile: filepath.Join(path, "init.pid"),
ConsoleSocket: socket,
IO: io,
NoPivot: r.NoPivot,
}
if err := p.runc.Create(context, r.ID, r.Bundle, opts); err != nil {
return nil, err
}
if r.Stdin != "" {
sc, err := fifo.OpenFifo(context, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return nil, err
}
p.closers = append(p.closers, sc)
}
if socket != nil {
console, err := socket.ReceiveMaster()
if err != nil {
return nil, err
}
p.console = console
if err := copyConsole(context, console, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup); err != nil {
return nil, err
}
} else {
if err := copyPipes(context, io, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup); err != nil {
return nil, err
}
}
pid, err := runc.ReadPidFile(opts.PidFile)
if err != nil {
return nil, err
}
p.pid = pid
return p, nil
}
func (p *initProcess) Pid() int {
return p.pid
}
func (p *initProcess) Status() int {
return p.status
}
// ContainerStatus return the state of the container (created, running, paused, stopped)
func (p *initProcess) ContainerStatus(ctx context.Context) (string, error) {
c, err := p.runc.State(ctx, p.id)
if err != nil {
return "", err
}
return c.Status, nil
}
func (p *initProcess) Start(context context.Context) error {
return p.runc.Start(context, p.id)
}
func (p *initProcess) Exited(status int) {
p.status = status
}
func (p *initProcess) Delete(context context.Context) error {
p.killAll(context)
p.Wait()
err := p.runc.Delete(context, p.id)
if p.io != nil {
for _, c := range p.closers {
c.Close()
}
p.io.Close()
}
return err
}
func (p *initProcess) Resize(ws console.WinSize) error {
if p.console == nil {
return nil
}
return p.console.Resize(ws)
}
func (p *initProcess) Pause(context context.Context) error {
return p.runc.Pause(context, p.id)
}
func (p *initProcess) Resume(context context.Context) error {
return p.runc.Resume(context, p.id)
}
func (p *initProcess) killAll(context context.Context) error {
return p.runc.Kill(context, p.id, int(syscall.SIGKILL), &runc.KillOpts{
All: true,
})
}