Skip to content

Commit 8ca4bfc

Browse files
committed
checkpoint: add support for containers with terminals
CRIU was extended to report about orphaned master pty-s via RPC. Signed-off-by: Andrei Vagin <[email protected]>
1 parent 8602083 commit 8ca4bfc

File tree

1 file changed

+51
-32
lines changed

1 file changed

+51
-32
lines changed

libcontainer/container_linux.go

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"io/ioutil"
11+
"net"
1112
"os"
1213
"os/exec"
1314
"path/filepath"
@@ -671,20 +672,21 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
671672
defer imageDir.Close()
672673

673674
rpcOpts := criurpc.CriuOpts{
674-
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
675-
WorkDirFd: proto.Int32(int32(workDir.Fd())),
676-
LogLevel: proto.Int32(4),
677-
LogFile: proto.String("dump.log"),
678-
Root: proto.String(c.config.Rootfs),
679-
ManageCgroups: proto.Bool(true),
680-
NotifyScripts: proto.Bool(true),
681-
Pid: proto.Int32(int32(c.initProcess.pid())),
682-
ShellJob: proto.Bool(criuOpts.ShellJob),
683-
LeaveRunning: proto.Bool(criuOpts.LeaveRunning),
684-
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
685-
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
686-
FileLocks: proto.Bool(criuOpts.FileLocks),
687-
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
675+
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
676+
WorkDirFd: proto.Int32(int32(workDir.Fd())),
677+
LogLevel: proto.Int32(4),
678+
LogFile: proto.String("dump.log"),
679+
Root: proto.String(c.config.Rootfs),
680+
ManageCgroups: proto.Bool(true),
681+
NotifyScripts: proto.Bool(true),
682+
Pid: proto.Int32(int32(c.initProcess.pid())),
683+
ShellJob: proto.Bool(criuOpts.ShellJob),
684+
LeaveRunning: proto.Bool(criuOpts.LeaveRunning),
685+
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
686+
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
687+
FileLocks: proto.Bool(criuOpts.FileLocks),
688+
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
689+
OrphanPtsMaster: proto.Bool(true),
688690
}
689691

690692
// append optional criu opts, e.g., page-server and port
@@ -852,20 +854,21 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
852854
req := &criurpc.CriuReq{
853855
Type: &t,
854856
Opts: &criurpc.CriuOpts{
855-
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
856-
WorkDirFd: proto.Int32(int32(workDir.Fd())),
857-
EvasiveDevices: proto.Bool(true),
858-
LogLevel: proto.Int32(4),
859-
LogFile: proto.String("restore.log"),
860-
RstSibling: proto.Bool(true),
861-
Root: proto.String(root),
862-
ManageCgroups: proto.Bool(true),
863-
NotifyScripts: proto.Bool(true),
864-
ShellJob: proto.Bool(criuOpts.ShellJob),
865-
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
866-
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
867-
FileLocks: proto.Bool(criuOpts.FileLocks),
868-
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
857+
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
858+
WorkDirFd: proto.Int32(int32(workDir.Fd())),
859+
EvasiveDevices: proto.Bool(true),
860+
LogLevel: proto.Int32(4),
861+
LogFile: proto.String("restore.log"),
862+
RstSibling: proto.Bool(true),
863+
Root: proto.String(root),
864+
ManageCgroups: proto.Bool(true),
865+
NotifyScripts: proto.Bool(true),
866+
ShellJob: proto.Bool(criuOpts.ShellJob),
867+
ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections),
868+
TcpEstablished: proto.Bool(criuOpts.TcpEstablished),
869+
FileLocks: proto.Bool(criuOpts.FileLocks),
870+
EmptyNs: proto.Uint32(criuOpts.EmptyNs),
871+
OrphanPtsMaster: proto.Bool(true),
869872
},
870873
}
871874

@@ -961,6 +964,11 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
961964

962965
logPath := filepath.Join(opts.WorkDirectory, req.GetOpts().GetLogFile())
963966
criuClient := os.NewFile(uintptr(fds[0]), "criu-transport-client")
967+
criuClientCon, err := net.FileConn(criuClient)
968+
if err != nil {
969+
return err
970+
}
971+
964972
criuServer := os.NewFile(uintptr(fds[1]), "criu-transport-server")
965973
defer criuClient.Close()
966974
defer criuServer.Close()
@@ -1020,14 +1028,15 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
10201028
if err != nil {
10211029
return err
10221030
}
1023-
_, err = criuClient.Write(data)
1031+
_, err = criuClientCon.Write(data)
10241032
if err != nil {
10251033
return err
10261034
}
10271035

10281036
buf := make([]byte, 10*4096)
1037+
oob := make([]byte, 4096)
10291038
for true {
1030-
n, err := criuClient.Read(buf)
1039+
n, oobn, _, _, err := criuClientCon.(*net.UnixConn).ReadMsgUnix(buf, oob)
10311040
if err != nil {
10321041
return err
10331042
}
@@ -1051,7 +1060,7 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
10511060
t := resp.GetType()
10521061
switch {
10531062
case t == criurpc.CriuReqType_NOTIFY:
1054-
if err := c.criuNotifications(resp, process, opts, extFds); err != nil {
1063+
if err := c.criuNotifications(resp, process, opts, extFds, oob[:oobn]); err != nil {
10551064
return err
10561065
}
10571066
t = criurpc.CriuReqType_NOTIFY
@@ -1135,11 +1144,12 @@ func unlockNetwork(config *configs.Config) error {
11351144
return nil
11361145
}
11371146

1138-
func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, opts *CriuOpts, fds []string) error {
1147+
func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, opts *CriuOpts, fds []string, oob []byte) error {
11391148
notify := resp.GetNotify()
11401149
if notify == nil {
11411150
return fmt.Errorf("invalid response: %s", resp.String())
11421151
}
1152+
logrus.Debugf("notify: %s\n", notify.GetScript())
11431153
switch {
11441154
case notify.GetScript() == "post-dump":
11451155
f, err := os.Create(filepath.Join(c.root, "checkpoint"))
@@ -1192,6 +1202,15 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
11921202
logrus.Error(err)
11931203
}
11941204
}
1205+
case notify.GetScript() == "orphan-pts-master":
1206+
scm, err := syscall.ParseSocketControlMessage(oob)
1207+
if err != nil {
1208+
return err
1209+
}
1210+
fds, err := syscall.ParseUnixRights(&scm[0])
1211+
1212+
process.consoleChan = make(chan *os.File, 1)
1213+
process.consoleChan <- os.NewFile(uintptr(fds[0]), "console")
11951214
}
11961215
return nil
11971216
}

0 commit comments

Comments
 (0)