From 60daa414db5158e06e335ea9b236f6021c8f36db Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 24 Apr 2018 20:10:25 +0300 Subject: [PATCH] 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 --- cmd/ctr/commands/tasks/tasks_unix.go | 31 ++++++++++++++-------------- linux/proc/init_state.go | 28 ++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/cmd/ctr/commands/tasks/tasks_unix.go b/cmd/ctr/commands/tasks/tasks_unix.go index ef563eec8..f7b111410 100644 --- a/cmd/ctr/commands/tasks/tasks_unix.go +++ b/cmd/ctr/commands/tasks/tasks_unix.go @@ -69,25 +69,24 @@ func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Consol // 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) { stdio := cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...) - if checkpoint == "" { - ioCreator := stdio + if checkpoint != "" { + im, err := client.GetImage(ctx, checkpoint) + if err != nil { + return nil, err + } + opts = append(opts, containerd.WithTaskCheckpoint(im)) + } + ioCreator := stdio + if tty { + ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio, cio.WithTerminal}, ioOpts...)...) + } + if nullIO { if tty { - ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio, cio.WithTerminal}, ioOpts...)...) + return nil, errors.New("tty and null-io cannot be used together") } - if nullIO { - if tty { - return nil, errors.New("tty and null-io cannot be used together") - } - ioCreator = cio.NullIO - } - return container.NewTask(ctx, ioCreator, opts...) + ioCreator = cio.NullIO } - im, err := client.GetImage(ctx, checkpoint) - if err != nil { - return nil, err - } - opts = append(opts, containerd.WithTaskCheckpoint(im)) - return container.NewTask(ctx, stdio, opts...) + return container.NewTask(ctx, ioCreator, opts...) } func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts { diff --git a/linux/proc/init_state.go b/linux/proc/init_state.go index 8944d6192..0cbdc7ac1 100644 --- a/linux/proc/init_state.go +++ b/linux/proc/init_state.go @@ -194,10 +194,23 @@ func (s *createdCheckpointState) Start(ctx context.Context) error { s.p.mu.Lock() defer s.p.mu.Unlock() 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 { return p.runtimeError(err, "OCI runtime restore failed") } - sio := p.stdio if sio.Stdin != "" { sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) if err != nil { @@ -207,7 +220,17 @@ func (s *createdCheckpointState) Start(ctx context.Context) error { p.closers = append(p.closers, sc) } 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, ©WaitGroup) + 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, ©WaitGroup); err != nil { 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") } p.pid = pid - return s.transition("running") }