Merge pull request #1371 from adrianreber/master

checkpoint: check if system supports pre-dumping
This commit is contained in:
Michael Crosby 2017-04-12 10:08:02 -07:00 committed by GitHub
commit f8ce01dbdc
1 changed files with 76 additions and 9 deletions

View File

@ -535,6 +535,56 @@ func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struc
return notifyMemoryPressure(c.cgroupManager.GetPaths(), level) return notifyMemoryPressure(c.cgroupManager.GetPaths(), level)
} }
var criuFeatures *criurpc.CriuFeatures
func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error {
var t criurpc.CriuReqType
t = criurpc.CriuReqType_FEATURE_CHECK
if err := c.checkCriuVersion("1.8"); 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
// some previous check
criuFeatures = nil
req := &criurpc.CriuReq{
Type: &t,
// Theoretically this should not be necessary but CRIU
// segfaults if Opts is empty.
// Fixed in CRIU 2.12
Opts: rpcOpts,
Features: criuFeat,
}
err := c.criuSwrk(nil, req, criuOpts, false)
if err != nil {
logrus.Debugf("%s", err)
return fmt.Errorf("CRIU feature check failed")
}
logrus.Debugf("Feature check says: %s", criuFeatures)
missingFeatures := false
if *criuFeat.MemTrack && !*criuFeatures.MemTrack {
missingFeatures = true
logrus.Debugf("CRIU does not support MemTrack")
}
if missingFeatures {
return fmt.Errorf("CRIU is missing features")
}
return nil
}
// 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 string) error { func (c *linuxContainer) checkCriuVersion(minVersion string) error {
var x, y, z, versionReq int var x, y, z, versionReq int
@ -717,6 +767,14 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
var t criurpc.CriuReqType var t criurpc.CriuReqType
if criuOpts.PreDump { if criuOpts.PreDump {
feat := criurpc.CriuFeatures{
MemTrack: proto.Bool(true),
}
if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil {
return err
}
t = criurpc.CriuReqType_PRE_DUMP t = criurpc.CriuReqType_PRE_DUMP
} else { } else {
t = criurpc.CriuReqType_DUMP t = criurpc.CriuReqType_DUMP
@ -1018,16 +1076,21 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
} }
logrus.Debugf("Using CRIU in %s mode", req.GetType().String()) logrus.Debugf("Using CRIU in %s mode", req.GetType().String())
val := reflect.ValueOf(req.GetOpts()) // In the case of criurpc.CriuReqType_FEATURE_CHECK req.GetOpts()
v := reflect.Indirect(val) // should be empty. For older CRIU versions it still will be
for i := 0; i < v.NumField(); i++ { // available but empty.
st := v.Type() if req.GetType() != criurpc.CriuReqType_FEATURE_CHECK {
name := st.Field(i).Name val := reflect.ValueOf(req.GetOpts())
if strings.HasPrefix(name, "XXX_") { v := reflect.Indirect(val)
continue for i := 0; i < v.NumField(); i++ {
st := v.Type()
name := st.Field(i).Name
if strings.HasPrefix(name, "XXX_") {
continue
}
value := val.MethodByName("Get" + name).Call([]reflect.Value{})
logrus.Debugf("CRIU option %s with value %v", name, value[0])
} }
value := val.MethodByName("Get" + name).Call([]reflect.Value{})
logrus.Debugf("CRIU option %s with value %v", name, value[0])
} }
data, err := proto.Marshal(req) data, err := proto.Marshal(req)
if err != nil { if err != nil {
@ -1063,6 +1126,10 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
t := resp.GetType() t := resp.GetType()
switch { switch {
case t == criurpc.CriuReqType_FEATURE_CHECK:
logrus.Debugf("Feature check says: %s", resp)
criuFeatures = resp.GetFeatures()
break
case t == criurpc.CriuReqType_NOTIFY: case t == criurpc.CriuReqType_NOTIFY:
if err := c.criuNotifications(resp, process, opts, extFds); err != nil { if err := c.criuNotifications(resp, process, opts, extFds); err != nil {
return err return err