mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
bfca1e6262
Now that CRIU has released Go bindings, this commit vendors those in. At first it only replaces the copy of RPC interface but the goal is to use CRIU functions from the Go bindings instead of replicating the functionality in runc. Signed-off-by: Adrian Reber <areber@redhat.com>
193 lines
3.7 KiB
Go
193 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/checkpoint-restore/go-criu"
|
|
"github.com/checkpoint-restore/go-criu/phaul"
|
|
"github.com/checkpoint-restore/go-criu/rpc"
|
|
"github.com/golang/protobuf/proto"
|
|
)
|
|
|
|
type testLocal struct {
|
|
criu.NoNotify
|
|
r *testRemote
|
|
}
|
|
|
|
type testRemote struct {
|
|
srv *phaul.Server
|
|
}
|
|
|
|
/* Dir where test will put dump images */
|
|
const imagesDir = "image"
|
|
|
|
func prepareImages() error {
|
|
err := os.Mkdir(imagesDir, 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
/* Work dir for PhaulClient */
|
|
err = os.Mkdir(imagesDir+"/local", 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
/* Work dir for PhaulServer */
|
|
err = os.Mkdir(imagesDir+"/remote", 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
/* Work dir for DumpCopyRestore */
|
|
err = os.Mkdir(imagesDir+"/test", 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func mergeImages(dumpDir, lastPreDumpDir string) error {
|
|
idir, err := os.Open(dumpDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer idir.Close()
|
|
|
|
imgs, err := idir.Readdirnames(0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, fname := range imgs {
|
|
if !strings.HasSuffix(fname, ".img") {
|
|
continue
|
|
}
|
|
|
|
fmt.Printf("\t%s -> %s/\n", fname, lastPreDumpDir)
|
|
err = syscall.Link(dumpDir+"/"+fname, lastPreDumpDir+"/"+fname)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *testRemote) doRestore() error {
|
|
lastSrvImagesDir := r.srv.LastImagesDir()
|
|
/*
|
|
* In imagesDir we have images from dump, in the
|
|
* lastSrvImagesDir -- where server-side images
|
|
* (from page server, with pages and pagemaps) are.
|
|
* Need to put former into latter and restore from
|
|
* them.
|
|
*/
|
|
err := mergeImages(imagesDir+"/test", lastSrvImagesDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
imgDir, err := os.Open(lastSrvImagesDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer imgDir.Close()
|
|
|
|
opts := rpc.CriuOpts{
|
|
LogLevel: proto.Int32(4),
|
|
LogFile: proto.String("restore.log"),
|
|
ImagesDirFd: proto.Int32(int32(imgDir.Fd())),
|
|
}
|
|
|
|
cr := r.srv.GetCriu()
|
|
fmt.Printf("Do restore\n")
|
|
return cr.Restore(opts, nil)
|
|
}
|
|
|
|
func (l *testLocal) PostDump() error {
|
|
return l.r.doRestore()
|
|
}
|
|
|
|
func (l *testLocal) DumpCopyRestore(cr *criu.Criu, cfg phaul.Config, lastClnImagesDir string) error {
|
|
fmt.Printf("Final stage\n")
|
|
|
|
imgDir, err := os.Open(imagesDir + "/test")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer imgDir.Close()
|
|
|
|
psi := rpc.CriuPageServerInfo{
|
|
Fd: proto.Int32(int32(cfg.Memfd)),
|
|
}
|
|
|
|
opts := rpc.CriuOpts{
|
|
Pid: proto.Int32(int32(cfg.Pid)),
|
|
LogLevel: proto.Int32(4),
|
|
LogFile: proto.String("dump.log"),
|
|
ImagesDirFd: proto.Int32(int32(imgDir.Fd())),
|
|
TrackMem: proto.Bool(true),
|
|
ParentImg: proto.String(lastClnImagesDir),
|
|
Ps: &psi,
|
|
}
|
|
|
|
fmt.Printf("Do dump\n")
|
|
return cr.Dump(opts, l)
|
|
}
|
|
|
|
func main() {
|
|
pid, _ := strconv.Atoi(os.Args[1])
|
|
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
|
|
if err != nil {
|
|
fmt.Printf("Can't make socketpair: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err = prepareImages()
|
|
if err != nil {
|
|
fmt.Printf("Can't prepare dirs for images: %v\n", err)
|
|
os.Exit(1)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Make server part (socket %d)\n", fds[1])
|
|
srv, err := phaul.MakePhaulServer(phaul.Config{
|
|
Pid: pid,
|
|
Memfd: fds[1],
|
|
Wdir: imagesDir + "/remote"})
|
|
if err != nil {
|
|
fmt.Printf("Unable to run a server: %v", err)
|
|
os.Exit(1)
|
|
return
|
|
}
|
|
|
|
r := &testRemote{srv}
|
|
|
|
fmt.Printf("Make client part (socket %d)\n", fds[0])
|
|
cln, err := phaul.MakePhaulClient(&testLocal{r: r}, srv,
|
|
phaul.Config{
|
|
Pid: pid,
|
|
Memfd: fds[0],
|
|
Wdir: imagesDir + "/local"})
|
|
if err != nil {
|
|
fmt.Printf("Unable to run a client: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("Migrate\n")
|
|
err = cln.Migrate()
|
|
if err != nil {
|
|
fmt.Printf("Failed: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("SUCCESS!\n")
|
|
}
|