Skip to content

Commit 747233b

Browse files
committed
lib: Add simple Go wrappers for swrk mode
We'll need some docs :) bu the API is criu := MakeCriu() criu.Dump(opts, notify) criu.Restore(opts, notify) criu.PreDump(opts, notify) criu.StartPageServer(opts) where opts is the object from rpc.proto, Go has almost native support for those, so caller should - compile .proto file - export it and golang/protobuf/proto - create and initialize the CriuOpts struct and notify is an interface with callbacks that correspond to criu notification messages. A stupid dump/restore tool in src/test/main.go demonstrates the above. Changes since v1: * Added keep_open mode for pre-dumps. Do use it one needs to call criu.Prepare() right after creation and criu.Cleanup() right after .Dump() * Report resp.cr_errmsg string on request error. Further TODO: - docs - code comments travis-ci: success for libphaul (rev2) Signed-off-by: Pavel Emelyanov <[email protected]>
1 parent 2510d3c commit 747233b

File tree

5 files changed

+352
-0
lines changed

5 files changed

+352
-0
lines changed

lib/go/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
src/rpc/rpc.pb.go

lib/go/Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
all: test
2+
3+
test: rpc
4+
GOPATH=$(shell pwd):/usr/share/gocode go build -o test test
5+
6+
rpc:
7+
mkdir -p src/rpc/
8+
protoc --go_out=src/rpc/ --proto_path=../../images/ ../../images/rpc.proto

lib/go/src/criu/main.go

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package criu
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/golang/protobuf/proto"
7+
"os"
8+
"os/exec"
9+
"rpc"
10+
"strconv"
11+
"syscall"
12+
)
13+
14+
type Criu struct {
15+
swrk_cmd *exec.Cmd
16+
swrk_sk *os.File
17+
}
18+
19+
func MakeCriu() *Criu {
20+
return &Criu{}
21+
}
22+
23+
func (c *Criu) Prepare() error {
24+
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0)
25+
if err != nil {
26+
return err
27+
}
28+
29+
cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln")
30+
syscall.CloseOnExec(fds[0])
31+
srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv")
32+
defer srv.Close()
33+
34+
args := []string{"swrk", strconv.Itoa(fds[1])}
35+
cmd := exec.Command("criu", args...)
36+
37+
err = cmd.Start()
38+
if err != nil {
39+
cln.Close()
40+
return err
41+
}
42+
43+
c.swrk_cmd = cmd
44+
c.swrk_sk = cln
45+
46+
return nil
47+
}
48+
49+
func (c *Criu) Cleanup() {
50+
if c.swrk_cmd != nil {
51+
c.swrk_sk.Close()
52+
c.swrk_sk = nil
53+
c.swrk_cmd.Wait()
54+
c.swrk_cmd = nil
55+
}
56+
}
57+
58+
func (c *Criu) sendAndRecv(req_b []byte) ([]byte, int, error) {
59+
cln := c.swrk_sk
60+
_, err := cln.Write(req_b)
61+
if err != nil {
62+
return nil, 0, err
63+
}
64+
65+
resp_b := make([]byte, 2*4096)
66+
n, err := cln.Read(resp_b)
67+
if err != nil {
68+
return nil, 0, err
69+
}
70+
71+
return resp_b, n, nil
72+
}
73+
74+
func (c *Criu) doSwrk(req_type rpc.CriuReqType, opts *rpc.CriuOpts, nfy CriuNotify) error {
75+
req := rpc.CriuReq{
76+
Type: &req_type,
77+
Opts: opts,
78+
}
79+
80+
if nfy != nil {
81+
opts.NotifyScripts = proto.Bool(true)
82+
}
83+
84+
if c.swrk_cmd == nil {
85+
err := c.Prepare()
86+
if err != nil {
87+
return err
88+
}
89+
90+
defer c.Cleanup()
91+
}
92+
93+
for {
94+
req_b, err := proto.Marshal(&req)
95+
if err != nil {
96+
return err
97+
}
98+
99+
resp_b, resp_s, err := c.sendAndRecv(req_b)
100+
if err != nil {
101+
return err
102+
}
103+
104+
resp := &rpc.CriuResp{}
105+
err = proto.Unmarshal(resp_b[:resp_s], resp)
106+
if err != nil {
107+
return err
108+
}
109+
110+
if !resp.GetSuccess() {
111+
return fmt.Errorf("operation failed (msg:%s err:%d)",
112+
resp.GetCrErrmsg(), resp.GetCrErrno())
113+
}
114+
115+
resp_type := resp.GetType()
116+
if resp_type == req_type {
117+
break
118+
}
119+
if resp_type != rpc.CriuReqType_NOTIFY {
120+
return errors.New("unexpected responce")
121+
}
122+
if nfy == nil {
123+
return errors.New("unexpected notify")
124+
}
125+
126+
notify := resp.GetNotify()
127+
switch notify.GetScript() {
128+
case "pre-dump":
129+
err = nfy.PreDump()
130+
case "post-dump":
131+
err = nfy.PostDump()
132+
case "pre-restore":
133+
err = nfy.PreRestore()
134+
case "post-restore":
135+
err = nfy.PostRestore(notify.GetPid())
136+
case "network-lock":
137+
err = nfy.NetworkLock()
138+
case "network-unlock":
139+
err = nfy.NetworkUnlock()
140+
case "setup-namespaces":
141+
err = nfy.SetupNamespaces(notify.GetPid())
142+
case "post-setup-namespaces":
143+
err = nfy.PostSetupNamespaces()
144+
case "post-resume":
145+
err = nfy.PostResume()
146+
default:
147+
err = nil
148+
}
149+
150+
if err != nil {
151+
return err
152+
}
153+
154+
req = rpc.CriuReq{
155+
Type: &resp_type,
156+
NotifySuccess: proto.Bool(true),
157+
}
158+
}
159+
160+
return nil
161+
}
162+
163+
func (c *Criu) Dump(opts rpc.CriuOpts, nfy CriuNotify) error {
164+
return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy)
165+
}
166+
167+
func (c *Criu) Restore(opts rpc.CriuOpts, nfy CriuNotify) error {
168+
return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy)
169+
}
170+
171+
func (c *Criu) PreDump(opts rpc.CriuOpts, nfy CriuNotify) error {
172+
return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy)
173+
}
174+
175+
func (c *Criu) StartPageServer(opts rpc.CriuOpts) error {
176+
return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil)
177+
}

lib/go/src/criu/notify.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package criu
2+
3+
type CriuNotify interface {
4+
PreDump() error
5+
PostDump() error
6+
PreRestore() error
7+
PostRestore(pid int32) error
8+
NetworkLock() error
9+
NetworkUnlock() error
10+
SetupNamespaces(pid int32) error
11+
PostSetupNamespaces() error
12+
PostResume() error
13+
}
14+
15+
type CriuNoNotify struct {
16+
}
17+
18+
func (c CriuNoNotify) PreDump() error {
19+
return nil
20+
}
21+
22+
func (c CriuNoNotify) PostDump() error {
23+
return nil
24+
}
25+
26+
func (c CriuNoNotify) PreRestore() error {
27+
return nil
28+
}
29+
30+
func (c CriuNoNotify) PostRestore(pid int32) error {
31+
return nil
32+
}
33+
34+
func (c CriuNoNotify) NetworkLock() error {
35+
return nil
36+
}
37+
38+
func (c CriuNoNotify) NetworkUnlock() error {
39+
return nil
40+
}
41+
42+
func (c CriuNoNotify) SetupNamespaces(pid int32) error {
43+
return nil
44+
}
45+
46+
func (c CriuNoNotify) PostSetupNamespaces() error {
47+
return nil
48+
}
49+
50+
func (c CriuNoNotify) PostResume() error {
51+
return nil
52+
}

lib/go/src/test/main.go

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package main
2+
3+
import (
4+
"criu"
5+
"fmt"
6+
"github.com/golang/protobuf/proto"
7+
"os"
8+
"rpc"
9+
"strconv"
10+
)
11+
12+
type TestNfy struct {
13+
criu.CriuNoNotify
14+
}
15+
16+
func (c TestNfy) PreDump() error {
17+
fmt.Printf("TEST PRE DUMP\n")
18+
return nil
19+
}
20+
21+
func doDump(c *criu.Criu, pid_s string, img_dir string, pre bool, prev_img string) error {
22+
fmt.Printf("Dumping\n")
23+
pid, _ := strconv.Atoi(pid_s)
24+
img, err := os.Open(img_dir)
25+
if err != nil {
26+
return fmt.Errorf("can't open image dir (%s)", err)
27+
}
28+
defer img.Close()
29+
30+
opts := rpc.CriuOpts{
31+
Pid: proto.Int32(int32(pid)),
32+
ImagesDirFd: proto.Int32(int32(img.Fd())),
33+
LogLevel: proto.Int32(4),
34+
LogFile: proto.String("dump.log"),
35+
}
36+
37+
if prev_img != "" {
38+
opts.ParentImg = proto.String(prev_img)
39+
opts.TrackMem = proto.Bool(true)
40+
}
41+
42+
if pre {
43+
err = c.PreDump(opts, TestNfy{})
44+
} else {
45+
err = c.Dump(opts, TestNfy{})
46+
}
47+
if err != nil {
48+
return fmt.Errorf("dump fail (%s)", err)
49+
}
50+
51+
return nil
52+
}
53+
54+
// Usage: test $act $pid $images_dir
55+
func main() {
56+
c := criu.MakeCriu()
57+
act := os.Args[1]
58+
switch act {
59+
case "dump":
60+
err := doDump(c, os.Args[2], os.Args[3], false, "")
61+
if err != nil {
62+
fmt.Print(err)
63+
os.Exit(1)
64+
}
65+
case "dump2":
66+
err := c.Prepare()
67+
if err != nil {
68+
fmt.Print(err)
69+
os.Exit(1)
70+
}
71+
72+
err = doDump(c, os.Args[2], os.Args[3]+"/pre", true, "")
73+
if err != nil {
74+
fmt.Printf("pre-dump failed")
75+
fmt.Print(err)
76+
os.Exit(1)
77+
}
78+
err = doDump(c, os.Args[2], os.Args[3], false, "./pre")
79+
if err != nil {
80+
fmt.Printf("dump failed")
81+
fmt.Print(err)
82+
os.Exit(1)
83+
}
84+
85+
c.Cleanup()
86+
case "restore":
87+
fmt.Printf("Restoring\n")
88+
img, err := os.Open(os.Args[2])
89+
if err != nil {
90+
fmt.Printf("can't open image dir")
91+
os.Exit(1)
92+
}
93+
defer img.Close()
94+
95+
opts := rpc.CriuOpts{
96+
ImagesDirFd: proto.Int32(int32(img.Fd())),
97+
LogLevel: proto.Int32(4),
98+
LogFile: proto.String("restore.log"),
99+
}
100+
101+
err = c.Restore(opts, nil)
102+
if err != nil {
103+
fmt.Printf("Error:")
104+
fmt.Print(err)
105+
fmt.Printf("\n")
106+
os.Exit(1)
107+
}
108+
default:
109+
fmt.Printf("unknown action\n")
110+
os.Exit(1)
111+
}
112+
113+
fmt.Printf("Success\n")
114+
}

0 commit comments

Comments
 (0)