Allow to checkpoint and restore a container with console

runc already supports this case, so we just need to run it with proper
options.

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
Andrei Vagin 2018-04-24 20:10:25 +03:00
parent 0846d6f8e9
commit 60daa414db
2 changed files with 40 additions and 19 deletions

View File

@ -69,7 +69,13 @@ func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Consol
// NewTask creates a new task // NewTask creates a new task
func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, tty, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) { func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, tty, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) {
stdio := cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...) stdio := cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...)
if checkpoint == "" { if checkpoint != "" {
im, err := client.GetImage(ctx, checkpoint)
if err != nil {
return nil, err
}
opts = append(opts, containerd.WithTaskCheckpoint(im))
}
ioCreator := stdio ioCreator := stdio
if tty { if tty {
ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio, cio.WithTerminal}, ioOpts...)...) ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio, cio.WithTerminal}, ioOpts...)...)
@ -81,13 +87,6 @@ func NewTask(ctx gocontext.Context, client *containerd.Client, container contain
ioCreator = cio.NullIO ioCreator = cio.NullIO
} }
return container.NewTask(ctx, ioCreator, opts...) return container.NewTask(ctx, ioCreator, opts...)
}
im, err := client.GetImage(ctx, checkpoint)
if err != nil {
return nil, err
}
opts = append(opts, containerd.WithTaskCheckpoint(im))
return container.NewTask(ctx, stdio, opts...)
} }
func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts { func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {

View File

@ -194,10 +194,23 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
s.p.mu.Lock() s.p.mu.Lock()
defer s.p.mu.Unlock() defer s.p.mu.Unlock()
p := s.p p := s.p
sio := p.stdio
var (
err error
socket *runc.Socket
)
if sio.Terminal {
if socket, err = runc.NewTempConsoleSocket(); err != nil {
return errors.Wrap(err, "failed to create OCI runtime console socket")
}
defer socket.Close()
s.opts.ConsoleSocket = socket
}
if _, err := s.p.runtime.Restore(ctx, p.id, p.bundle, s.opts); err != nil { if _, err := s.p.runtime.Restore(ctx, p.id, p.bundle, s.opts); err != nil {
return p.runtimeError(err, "OCI runtime restore failed") return p.runtimeError(err, "OCI runtime restore failed")
} }
sio := p.stdio
if sio.Stdin != "" { if sio.Stdin != "" {
sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil { if err != nil {
@ -207,7 +220,17 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
p.closers = append(p.closers, sc) p.closers = append(p.closers, sc)
} }
var copyWaitGroup sync.WaitGroup var copyWaitGroup sync.WaitGroup
if !sio.IsNull() { if socket != nil {
console, err := socket.ReceiveMaster()
if err != nil {
return errors.Wrap(err, "failed to retrieve console master")
}
console, err = p.platform.CopyConsole(ctx, console, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, &copyWaitGroup)
if err != nil {
return errors.Wrap(err, "failed to start console copy")
}
p.console = console
} else if !sio.IsNull() {
if err := copyPipes(ctx, p.io, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, &copyWaitGroup); err != nil { if err := copyPipes(ctx, p.io, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, &copyWaitGroup); err != nil {
return errors.Wrap(err, "failed to start io pipe copy") return errors.Wrap(err, "failed to start io pipe copy")
} }
@ -219,7 +242,6 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
return errors.Wrap(err, "failed to retrieve OCI runtime container pid") return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
} }
p.pid = pid p.pid = pid
return s.transition("running") return s.transition("running")
} }