Merge pull request #2409 from adrianreber/go-criu-4-0-0
Update to latest go-criu
This commit is contained in:
commit
cd4b71c27a
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module github.com/opencontainers/runc
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5
|
github.com/checkpoint-restore/go-criu/v4 v4.0.2
|
||||||
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3
|
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3
|
||||||
github.com/containerd/console v1.0.0
|
github.com/containerd/console v1.0.0
|
||||||
github.com/coreos/go-systemd/v22 v22.0.0
|
github.com/coreos/go-systemd/v22 v22.0.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,6 +1,6 @@
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5 h1:950diauOSoCNaQfvLE0WaFadyI/ilKIjb6jEUQnm+hE=
|
github.com/checkpoint-restore/go-criu/v4 v4.0.2 h1:jt+rnBIhFtPw0fhtpYGcUOilh4aO9Hj7r+YLEtf30uA=
|
||||||
github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
|
github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||||
github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f h1:W1RQPz3nR8RxUw/Uqk71GU3JlZ7pNa1pXrHs98h0o9U=
|
github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f h1:W1RQPz3nR8RxUw/Uqk71GU3JlZ7pNa1pXrHs98h0o9U=
|
||||||
github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
|
github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
|
||||||
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3 h1:qcqzLJa2xCo9sgdCzpT/SJSYxROTEstuhf7ZBHMirms=
|
github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3 h1:qcqzLJa2xCo9sgdCzpT/SJSYxROTEstuhf7ZBHMirms=
|
||||||
|
|
|
@ -26,7 +26,8 @@ import (
|
||||||
"github.com/opencontainers/runc/libcontainer/utils"
|
"github.com/opencontainers/runc/libcontainer/utils"
|
||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
|
||||||
criurpc "github.com/checkpoint-restore/go-criu/rpc"
|
"github.com/checkpoint-restore/go-criu/v4"
|
||||||
|
criurpc "github.com/checkpoint-restore/go-criu/v4/rpc"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
@ -674,16 +675,6 @@ func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.
|
||||||
var t criurpc.CriuReqType
|
var t criurpc.CriuReqType
|
||||||
t = criurpc.CriuReqType_FEATURE_CHECK
|
t = criurpc.CriuReqType_FEATURE_CHECK
|
||||||
|
|
||||||
// criu 1.8 => 10800
|
|
||||||
if err := c.checkCriuVersion(10800); err != nil {
|
|
||||||
// Feature checking was introduced with CRIU 1.8.
|
|
||||||
// Ignore the feature check if an older CRIU version is used
|
|
||||||
// and just act as before.
|
|
||||||
// As all automated PR testing is done using CRIU 1.7 this
|
|
||||||
// code will not be tested by automated PR testing.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the features we are looking for are really not from
|
// make sure the features we are looking for are really not from
|
||||||
// some previous check
|
// some previous check
|
||||||
criuFeatures = nil
|
criuFeatures = nil
|
||||||
|
@ -733,50 +724,6 @@ func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCriuVersion(path string) (int, error) {
|
|
||||||
var x, y, z int
|
|
||||||
|
|
||||||
out, err := exec.Command(path, "-V").Output()
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("Unable to execute CRIU command: %s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
x = 0
|
|
||||||
y = 0
|
|
||||||
z = 0
|
|
||||||
if ep := strings.Index(string(out), "-"); ep >= 0 {
|
|
||||||
// criu Git version format
|
|
||||||
var version string
|
|
||||||
if sp := strings.Index(string(out), "GitID"); sp > 0 {
|
|
||||||
version = string(out)[sp:ep]
|
|
||||||
} else {
|
|
||||||
return 0, fmt.Errorf("Unable to parse the CRIU version: %s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := fmt.Sscanf(version, "GitID: v%d.%d.%d", &x, &y, &z) // 1.5.2
|
|
||||||
if err != nil {
|
|
||||||
n, err = fmt.Sscanf(version, "GitID: v%d.%d", &x, &y) // 1.6
|
|
||||||
y++
|
|
||||||
} else {
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
if n < 2 || err != nil {
|
|
||||||
return 0, fmt.Errorf("Unable to parse the CRIU version: %s %d %s", version, n, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// criu release version format
|
|
||||||
n, err := fmt.Sscanf(string(out), "Version: %d.%d.%d\n", &x, &y, &z) // 1.5.2
|
|
||||||
if err != nil {
|
|
||||||
n, err = fmt.Sscanf(string(out), "Version: %d.%d\n", &x, &y) // 1.6
|
|
||||||
}
|
|
||||||
if n < 2 || err != nil {
|
|
||||||
return 0, fmt.Errorf("Unable to parse the CRIU version: %s %d %s", out, n, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return x*10000 + y*100 + z, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareCriuVersion(criuVersion int, minVersion int) error {
|
func compareCriuVersion(criuVersion int, minVersion int) error {
|
||||||
// simple function to perform the actual version compare
|
// simple function to perform the actual version compare
|
||||||
if criuVersion < minVersion {
|
if criuVersion < minVersion {
|
||||||
|
@ -786,9 +733,6 @@ func compareCriuVersion(criuVersion int, minVersion int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used to store the result of criu version RPC
|
|
||||||
var criuVersionRPC *criurpc.CriuVersion
|
|
||||||
|
|
||||||
// checkCriuVersion checks Criu version greater than or equal to minVersion
|
// checkCriuVersion checks Criu version greater than or equal to minVersion
|
||||||
func (c *linuxContainer) checkCriuVersion(minVersion int) error {
|
func (c *linuxContainer) checkCriuVersion(minVersion int) error {
|
||||||
|
|
||||||
|
@ -798,50 +742,13 @@ func (c *linuxContainer) checkCriuVersion(minVersion int) error {
|
||||||
return compareCriuVersion(c.criuVersion, minVersion)
|
return compareCriuVersion(c.criuVersion, minVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// First try if this version of CRIU support the version RPC.
|
criu := criu.MakeCriu()
|
||||||
// The CRIU version RPC was introduced with CRIU 3.0.
|
var err error
|
||||||
|
c.criuVersion, err = criu.GetCriuVersion()
|
||||||
// First, reset the variable for the RPC answer to nil
|
|
||||||
criuVersionRPC = nil
|
|
||||||
|
|
||||||
var t criurpc.CriuReqType
|
|
||||||
t = criurpc.CriuReqType_VERSION
|
|
||||||
req := &criurpc.CriuReq{
|
|
||||||
Type: &t,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := c.criuSwrk(nil, req, nil, false, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CRIU version check failed: %s", err)
|
return fmt.Errorf("CRIU version check failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if criuVersionRPC != nil {
|
|
||||||
logrus.Debugf("CRIU version: %s", criuVersionRPC)
|
|
||||||
// major and minor are always set
|
|
||||||
c.criuVersion = int(*criuVersionRPC.Major) * 10000
|
|
||||||
c.criuVersion += int(*criuVersionRPC.Minor) * 100
|
|
||||||
if criuVersionRPC.Sublevel != nil {
|
|
||||||
c.criuVersion += int(*criuVersionRPC.Sublevel)
|
|
||||||
}
|
|
||||||
if criuVersionRPC.Gitid != nil {
|
|
||||||
// runc's convention is that a CRIU git release is
|
|
||||||
// always the same as increasing the minor by 1
|
|
||||||
c.criuVersion -= (c.criuVersion % 100)
|
|
||||||
c.criuVersion += 100
|
|
||||||
}
|
|
||||||
return compareCriuVersion(c.criuVersion, minVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is CRIU without the version RPC and therefore
|
|
||||||
// older than 3.0. Parsing the output is required.
|
|
||||||
|
|
||||||
// This can be remove once runc does not work with criu older than 3.0
|
|
||||||
|
|
||||||
c.criuVersion, err = parseCriuVersion(c.criuPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return compareCriuVersion(c.criuVersion, minVersion)
|
return compareCriuVersion(c.criuVersion, minVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -918,8 +825,8 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||||
// support for doing unprivileged dumps, but the setup of
|
// support for doing unprivileged dumps, but the setup of
|
||||||
// rootless containers might make this complicated.
|
// rootless containers might make this complicated.
|
||||||
|
|
||||||
// criu 1.5.2 => 10502
|
// We are relying on the CRIU version RPC which was introduced with CRIU 3.0.0
|
||||||
if err := c.checkCriuVersion(10502); err != nil {
|
if err := c.checkCriuVersion(30000); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,10 +934,6 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||||
|
|
||||||
// append optional manage cgroups mode
|
// append optional manage cgroups mode
|
||||||
if criuOpts.ManageCgroupsMode != 0 {
|
if criuOpts.ManageCgroupsMode != 0 {
|
||||||
// criu 1.7 => 10700
|
|
||||||
if err := c.checkCriuVersion(10700); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode)
|
mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode)
|
||||||
rpcOpts.ManageCgroupsMode = &mode
|
rpcOpts.ManageCgroupsMode = &mode
|
||||||
}
|
}
|
||||||
|
@ -1250,8 +1153,8 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||||
// TODO(avagin): Figure out how to make this work nicely. CRIU doesn't have
|
// TODO(avagin): Figure out how to make this work nicely. CRIU doesn't have
|
||||||
// support for unprivileged restore at the moment.
|
// support for unprivileged restore at the moment.
|
||||||
|
|
||||||
// criu 1.5.2 => 10502
|
// We are relying on the CRIU version RPC which was introduced with CRIU 3.0.0
|
||||||
if err := c.checkCriuVersion(10502); err != nil {
|
if err := c.checkCriuVersion(30000); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if criuOpts.WorkDirectory == "" {
|
if criuOpts.WorkDirectory == "" {
|
||||||
|
@ -1394,10 +1297,6 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||||
|
|
||||||
// append optional manage cgroups mode
|
// append optional manage cgroups mode
|
||||||
if criuOpts.ManageCgroupsMode != 0 {
|
if criuOpts.ManageCgroupsMode != 0 {
|
||||||
// criu 1.7 => 10700
|
|
||||||
if err := c.checkCriuVersion(10700); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode)
|
mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode)
|
||||||
req.Opts.ManageCgroupsMode = &mode
|
req.Opts.ManageCgroupsMode = &mode
|
||||||
}
|
}
|
||||||
|
@ -1586,20 +1485,11 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
|
||||||
}
|
}
|
||||||
if !resp.GetSuccess() {
|
if !resp.GetSuccess() {
|
||||||
typeString := req.GetType().String()
|
typeString := req.GetType().String()
|
||||||
if typeString == "VERSION" {
|
|
||||||
// If the VERSION RPC fails this probably means that the CRIU
|
|
||||||
// version is too old for this RPC. Just return 'nil'.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("criu failed: type %s errno %d\nlog file: %s", typeString, resp.GetCrErrno(), logPath)
|
return fmt.Errorf("criu failed: type %s errno %d\nlog file: %s", typeString, resp.GetCrErrno(), logPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
t := resp.GetType()
|
t := resp.GetType()
|
||||||
switch {
|
switch {
|
||||||
case t == criurpc.CriuReqType_VERSION:
|
|
||||||
logrus.Debugf("CRIU version: %s", resp)
|
|
||||||
criuVersionRPC = resp.GetVersion()
|
|
||||||
break
|
|
||||||
case t == criurpc.CriuReqType_FEATURE_CHECK:
|
case t == criurpc.CriuReqType_FEATURE_CHECK:
|
||||||
logrus.Debugf("Feature check says: %s", resp)
|
logrus.Debugf("Feature check says: %s", resp)
|
||||||
criuFeatures = resp.GetFeatures()
|
criuFeatures = resp.GetFeatures()
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
||||||
|
test/test
|
||||||
|
test/piggie
|
||||||
|
test/phaul
|
||||||
|
image
|
||||||
|
rpc/rpc.proto
|
|
@ -0,0 +1,25 @@
|
||||||
|
language: go
|
||||||
|
sudo: required
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
go:
|
||||||
|
- "1.14.x"
|
||||||
|
- "1.13.x"
|
||||||
|
- tip
|
||||||
|
env:
|
||||||
|
# Run the tests with CRIU master and criu-dev
|
||||||
|
- CRIU_BRANCH="master"
|
||||||
|
- CRIU_BRANCH="criu-dev"
|
||||||
|
install:
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install -y libprotobuf-dev libprotobuf-c0-dev protobuf-c-compiler protobuf-compiler python-protobuf libnl-3-dev libnet-dev libcap-dev
|
||||||
|
- go get github.com/checkpoint-restore/go-criu
|
||||||
|
- git clone --single-branch -b ${CRIU_BRANCH} https://github.com/checkpoint-restore/criu.git
|
||||||
|
- cd criu; make
|
||||||
|
- sudo install -D -m 755 criu/criu /usr/sbin/
|
||||||
|
- cd ..
|
||||||
|
script:
|
||||||
|
# This builds the code without running the tests.
|
||||||
|
- make build phaul test/test test/phaul test/piggie
|
||||||
|
# Run actual test as root as it uses CRIU.
|
||||||
|
- sudo make test phaul-test
|
|
@ -0,0 +1,60 @@
|
||||||
|
GO ?= go
|
||||||
|
CC ?= gcc
|
||||||
|
ifeq ($(GOPATH),)
|
||||||
|
export GOPATH := $(shell $(GO) env GOPATH)
|
||||||
|
endif
|
||||||
|
FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH)))
|
||||||
|
GOBIN := $(shell $(GO) env GOBIN)
|
||||||
|
ifeq ($(GOBIN),)
|
||||||
|
GOBIN := $(FIRST_GOPATH)/bin
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: build test phaul phaul-test
|
||||||
|
|
||||||
|
lint:
|
||||||
|
@golint . test phaul
|
||||||
|
build:
|
||||||
|
@$(GO) build -v
|
||||||
|
|
||||||
|
test/piggie: test/piggie.c
|
||||||
|
@$(CC) $^ -o $@
|
||||||
|
|
||||||
|
test/test: test/main.go
|
||||||
|
@$(GO) build -v -o test/test test/main.go
|
||||||
|
|
||||||
|
test: test/test test/piggie
|
||||||
|
mkdir -p image
|
||||||
|
test/piggie
|
||||||
|
test/test dump `pidof piggie` image
|
||||||
|
test/test restore image
|
||||||
|
pkill -9 piggie || :
|
||||||
|
|
||||||
|
phaul:
|
||||||
|
@cd phaul; go build -v
|
||||||
|
|
||||||
|
test/phaul: test/phaul-main.go
|
||||||
|
@$(GO) build -v -o test/phaul test/phaul-main.go
|
||||||
|
|
||||||
|
phaul-test: test/phaul test/piggie
|
||||||
|
rm -rf image
|
||||||
|
test/piggie
|
||||||
|
test/phaul `pidof piggie`
|
||||||
|
pkill -9 piggie || :
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f test/test test/piggie test/phaul
|
||||||
|
@rm -rf image
|
||||||
|
@rm -f rpc/rpc.proto
|
||||||
|
|
||||||
|
install.tools:
|
||||||
|
if [ ! -x "$(GOBIN)/golint" ]; then \
|
||||||
|
$(GO) get -u golang.org/x/lint/golint; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
rpc/rpc.proto:
|
||||||
|
curl -s https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@
|
||||||
|
|
||||||
|
rpc/rpc.pb.go: rpc/rpc.proto
|
||||||
|
protoc --go_out=. $^
|
||||||
|
|
||||||
|
.PHONY: build test clean lint phaul
|
|
@ -0,0 +1,75 @@
|
||||||
|
[![master](https://travis-ci.org/checkpoint-restore/go-criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/go-criu)
|
||||||
|
|
||||||
|
## go-criu -- Go bindings for [CRIU](https://criu.org/)
|
||||||
|
|
||||||
|
This repository provides Go bindings for CRIU. The code is based on the Go based PHaul
|
||||||
|
implementation from the CRIU repository. For easier inclusion into other Go projects the
|
||||||
|
CRIU Go bindings have been moved to this repository.
|
||||||
|
|
||||||
|
The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need
|
||||||
|
to set up all the infrastructure to make the actual RPC connection to CRIU.
|
||||||
|
|
||||||
|
The following example would print the version of CRIU:
|
||||||
|
```
|
||||||
|
c := criu.MakeCriu()
|
||||||
|
version, err := c.GetCriuVersion()
|
||||||
|
fmt.Println(version)
|
||||||
|
```
|
||||||
|
or to just check if at least a certain CRIU version is installed:
|
||||||
|
```
|
||||||
|
c := criu.MakeCriu()
|
||||||
|
result, err := c.IsCriuAtLeast(31100)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
The first go-criu release was 3.11 based on CRIU 3.11. The initial plan
|
||||||
|
was to follow CRIU so that go-criu would carry the same version number as
|
||||||
|
CRIU.
|
||||||
|
|
||||||
|
As go-criu is imported in other projects and as Go modules are expected
|
||||||
|
to follow Semantic Versioning go-criu will also follow Semantic Versioning
|
||||||
|
starting with the 4.0.0 release.
|
||||||
|
|
||||||
|
4.0.0 is based on CRIU 3.14
|
||||||
|
|
||||||
|
## How to contribute
|
||||||
|
|
||||||
|
While bug fixes can first be identified via an "issue", that is not required.
|
||||||
|
It's ok to just open up a PR with the fix, but make sure you include the same
|
||||||
|
information you would have included in an issue - like how to reproduce it.
|
||||||
|
|
||||||
|
PRs for new features should include some background on what use cases the
|
||||||
|
new code is trying to address. When possible and when it makes sense, try to
|
||||||
|
break-up larger PRs into smaller ones - it's easier to review smaller
|
||||||
|
code changes. But only if those smaller ones make sense as stand-alone PRs.
|
||||||
|
|
||||||
|
Regardless of the type of PR, all PRs should include:
|
||||||
|
* well documented code changes
|
||||||
|
* additional testcases. Ideally, they should fail w/o your code change applied
|
||||||
|
* documentation changes
|
||||||
|
|
||||||
|
Squash your commits into logical pieces of work that might want to be reviewed
|
||||||
|
separate from the rest of the PRs. Ideally, each commit should implement a
|
||||||
|
single idea, and the PR branch should pass the tests at every commit. GitHub
|
||||||
|
makes it easy to review the cumulative effect of many commits; so, when in
|
||||||
|
doubt, use smaller commits.
|
||||||
|
|
||||||
|
PRs that fix issues should include a reference like `Closes #XXXX` in the
|
||||||
|
commit message so that github will automatically close the referenced issue
|
||||||
|
when the PR is merged.
|
||||||
|
|
||||||
|
Contributors must assert that they are in compliance with the [Developer
|
||||||
|
Certificate of Origin 1.1](http://developercertificate.org/). This is achieved
|
||||||
|
by adding a "Signed-off-by" line containing the contributor's name and e-mail
|
||||||
|
to every commit message. Your signature certifies that you wrote the patch or
|
||||||
|
otherwise have the right to pass it on as an open-source patch.
|
||||||
|
|
||||||
|
### License and copyright
|
||||||
|
|
||||||
|
Unless mentioned otherwise in a specific file's header, all code in
|
||||||
|
this project is released under the Apache 2.0 license.
|
||||||
|
|
||||||
|
The author of a change remains the copyright holder of their code
|
||||||
|
(no copyright assignment). The list of authors and contributors can be
|
||||||
|
retrieved from the git commit history and in some cases, the file headers.
|
|
@ -0,0 +1,5 @@
|
||||||
|
module github.com/checkpoint-restore/go-criu/v4
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require github.com/golang/protobuf v1.3.5
|
|
@ -0,0 +1,20 @@
|
||||||
|
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
@ -0,0 +1,250 @@
|
||||||
|
package criu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/checkpoint-restore/go-criu/v4/rpc"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Criu struct
|
||||||
|
type Criu struct {
|
||||||
|
swrkCmd *exec.Cmd
|
||||||
|
swrkSk *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeCriu returns the Criu object required for most operations
|
||||||
|
func MakeCriu() *Criu {
|
||||||
|
return &Criu{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare sets up everything for the RPC communication to CRIU
|
||||||
|
func (c *Criu) Prepare() error {
|
||||||
|
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln")
|
||||||
|
syscall.CloseOnExec(fds[0])
|
||||||
|
srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv")
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
args := []string{"swrk", strconv.Itoa(fds[1])}
|
||||||
|
cmd := exec.Command("criu", args...)
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
cln.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.swrkCmd = cmd
|
||||||
|
c.swrkSk = cln
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup cleans up
|
||||||
|
func (c *Criu) Cleanup() {
|
||||||
|
if c.swrkCmd != nil {
|
||||||
|
c.swrkSk.Close()
|
||||||
|
c.swrkSk = nil
|
||||||
|
c.swrkCmd.Wait()
|
||||||
|
c.swrkCmd = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) {
|
||||||
|
cln := c.swrkSk
|
||||||
|
_, err := cln.Write(reqB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
respB := make([]byte, 2*4096)
|
||||||
|
n, err := cln.Read(respB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return respB, n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error {
|
||||||
|
resp, err := c.doSwrkWithResp(reqType, opts, nfy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
respType := resp.GetType()
|
||||||
|
if respType != reqType {
|
||||||
|
return errors.New("unexpected responce")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) {
|
||||||
|
var resp *rpc.CriuResp
|
||||||
|
|
||||||
|
req := rpc.CriuReq{
|
||||||
|
Type: &reqType,
|
||||||
|
Opts: opts,
|
||||||
|
}
|
||||||
|
|
||||||
|
if nfy != nil {
|
||||||
|
opts.NotifyScripts = proto.Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.swrkCmd == nil {
|
||||||
|
err := c.Prepare()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.Cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
reqB, err := proto.Marshal(&req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
respB, respS, err := c.sendAndRecv(reqB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = &rpc.CriuResp{}
|
||||||
|
err = proto.Unmarshal(respB[:respS], resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !resp.GetSuccess() {
|
||||||
|
return resp, fmt.Errorf("operation failed (msg:%s err:%d)",
|
||||||
|
resp.GetCrErrmsg(), resp.GetCrErrno())
|
||||||
|
}
|
||||||
|
|
||||||
|
respType := resp.GetType()
|
||||||
|
if respType != rpc.CriuReqType_NOTIFY {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nfy == nil {
|
||||||
|
return resp, errors.New("unexpected notify")
|
||||||
|
}
|
||||||
|
|
||||||
|
notify := resp.GetNotify()
|
||||||
|
switch notify.GetScript() {
|
||||||
|
case "pre-dump":
|
||||||
|
err = nfy.PreDump()
|
||||||
|
case "post-dump":
|
||||||
|
err = nfy.PostDump()
|
||||||
|
case "pre-restore":
|
||||||
|
err = nfy.PreRestore()
|
||||||
|
case "post-restore":
|
||||||
|
err = nfy.PostRestore(notify.GetPid())
|
||||||
|
case "network-lock":
|
||||||
|
err = nfy.NetworkLock()
|
||||||
|
case "network-unlock":
|
||||||
|
err = nfy.NetworkUnlock()
|
||||||
|
case "setup-namespaces":
|
||||||
|
err = nfy.SetupNamespaces(notify.GetPid())
|
||||||
|
case "post-setup-namespaces":
|
||||||
|
err = nfy.PostSetupNamespaces()
|
||||||
|
case "post-resume":
|
||||||
|
err = nfy.PostResume()
|
||||||
|
default:
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req = rpc.CriuReq{
|
||||||
|
Type: &respType,
|
||||||
|
NotifySuccess: proto.Bool(true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump dumps a process
|
||||||
|
func (c *Criu) Dump(opts rpc.CriuOpts, nfy Notify) error {
|
||||||
|
return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores a process
|
||||||
|
func (c *Criu) Restore(opts rpc.CriuOpts, nfy Notify) error {
|
||||||
|
return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreDump does a pre-dump
|
||||||
|
func (c *Criu) PreDump(opts rpc.CriuOpts, nfy Notify) error {
|
||||||
|
return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartPageServer starts the page server
|
||||||
|
func (c *Criu) StartPageServer(opts rpc.CriuOpts) error {
|
||||||
|
return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartPageServerChld starts the page server and returns PID and port
|
||||||
|
func (c *Criu) StartPageServerChld(opts rpc.CriuOpts) (int, int, error) {
|
||||||
|
resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, &opts, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(resp.Ps.GetPid()), int(resp.Ps.GetPort()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCriuVersion executes the VERSION RPC call and returns the version
|
||||||
|
// as an integer. Major * 10000 + Minor * 100 + SubLevel
|
||||||
|
func (c *Criu) GetCriuVersion() (int, error) {
|
||||||
|
resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.GetType() != rpc.CriuReqType_VERSION {
|
||||||
|
return 0, fmt.Errorf("Unexpected CRIU RPC response")
|
||||||
|
}
|
||||||
|
|
||||||
|
version := int(*resp.GetVersion().MajorNumber) * 10000
|
||||||
|
version += int(*resp.GetVersion().MinorNumber) * 100
|
||||||
|
if resp.GetVersion().Sublevel != nil {
|
||||||
|
version += int(*resp.GetVersion().Sublevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.GetVersion().Gitid != nil {
|
||||||
|
// taken from runc: if it is a git release -> increase minor by 1
|
||||||
|
version -= (version % 100)
|
||||||
|
version += 100
|
||||||
|
}
|
||||||
|
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCriuAtLeast checks if the version is at least the same
|
||||||
|
// as the parameter version
|
||||||
|
func (c *Criu) IsCriuAtLeast(version int) (bool, error) {
|
||||||
|
criuVersion, err := c.GetCriuVersion()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if criuVersion >= version {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package criu
|
||||||
|
|
||||||
|
//Notify interface
|
||||||
|
type Notify interface {
|
||||||
|
PreDump() error
|
||||||
|
PostDump() error
|
||||||
|
PreRestore() error
|
||||||
|
PostRestore(pid int32) error
|
||||||
|
NetworkLock() error
|
||||||
|
NetworkUnlock() error
|
||||||
|
SetupNamespaces(pid int32) error
|
||||||
|
PostSetupNamespaces() error
|
||||||
|
PostResume() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoNotify struct
|
||||||
|
type NoNotify struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreDump NoNotify
|
||||||
|
func (c NoNotify) PreDump() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostDump NoNotify
|
||||||
|
func (c NoNotify) PostDump() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreRestore NoNotify
|
||||||
|
func (c NoNotify) PreRestore() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostRestore NoNotify
|
||||||
|
func (c NoNotify) PostRestore(pid int32) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkLock NoNotify
|
||||||
|
func (c NoNotify) NetworkLock() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkUnlock NoNotify
|
||||||
|
func (c NoNotify) NetworkUnlock() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupNamespaces NoNotify
|
||||||
|
func (c NoNotify) SetupNamespaces(pid int32) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostSetupNamespaces NoNotify
|
||||||
|
func (c NoNotify) PostSetupNamespaces() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostResume NoNotify
|
||||||
|
func (c NoNotify) PostResume() error {
|
||||||
|
return nil
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
||||||
# github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5
|
# github.com/checkpoint-restore/go-criu/v4 v4.0.2
|
||||||
## explicit
|
## explicit
|
||||||
github.com/checkpoint-restore/go-criu/rpc
|
github.com/checkpoint-restore/go-criu/v4
|
||||||
|
github.com/checkpoint-restore/go-criu/v4/rpc
|
||||||
# github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3
|
# github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3
|
||||||
## explicit
|
## explicit
|
||||||
github.com/cilium/ebpf
|
github.com/cilium/ebpf
|
||||||
|
|
Loading…
Reference in New Issue