Make state detection precise
Fixes: https://github.com/opencontainers/runc/issues/871 Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
This commit is contained in:
parent
629e35666d
commit
14e95b2aa9
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/opencontainers/runc/libcontainer/criurpc"
|
"github.com/opencontainers/runc/libcontainer/criurpc"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/system"
|
||||||
"github.com/opencontainers/runc/libcontainer/utils"
|
"github.com/opencontainers/runc/libcontainer/utils"
|
||||||
"github.com/syndtr/gocapability/capability"
|
"github.com/syndtr/gocapability/capability"
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
@ -37,6 +38,7 @@ type linuxContainer struct {
|
||||||
initPath string
|
initPath string
|
||||||
initArgs []string
|
initArgs []string
|
||||||
initProcess parentProcess
|
initProcess parentProcess
|
||||||
|
initProcessStartTime string
|
||||||
criuPath string
|
criuPath string
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
criuVersion int
|
criuVersion int
|
||||||
|
@ -252,9 +254,12 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
|
||||||
c.state = &createdState{
|
c.state = &createdState{
|
||||||
c: c,
|
c: c,
|
||||||
}
|
}
|
||||||
if err := c.updateState(parent); err != nil {
|
state, err := c.updateState(parent)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
c.initProcessStartTime = state.InitProcessStartTime
|
||||||
|
|
||||||
if c.config.Hooks != nil {
|
if c.config.Hooks != nil {
|
||||||
s := configs.HookState{
|
s := configs.HookState{
|
||||||
Version: c.config.Version,
|
Version: c.config.Version,
|
||||||
|
@ -1043,7 +1048,7 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := c.updateState(r); err != nil {
|
if _, err := c.updateState(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.Remove(filepath.Join(c.root, "checkpoint")); err != nil {
|
if err := os.Remove(filepath.Join(c.root, "checkpoint")); err != nil {
|
||||||
|
@ -1055,13 +1060,17 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) updateState(process parentProcess) error {
|
func (c *linuxContainer) updateState(process parentProcess) (*State, error) {
|
||||||
c.initProcess = process
|
c.initProcess = process
|
||||||
state, err := c.currentState()
|
state, err := c.currentState()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.saveState(state)
|
err = c.saveState(state)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) saveState(s *State) error {
|
func (c *linuxContainer) saveState(s *State) error {
|
||||||
|
@ -1109,6 +1118,21 @@ func (c *linuxContainer) refreshState() error {
|
||||||
return c.state.transition(&stoppedState{c: c})
|
return c.state.transition(&stoppedState{c: c})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doesInitProcessExist checks if the init process is still the same process
|
||||||
|
// as the initial one, it could happen that the original process has exited
|
||||||
|
// and a new process has been created with the same pid, in this case, the
|
||||||
|
// container would already be stopped.
|
||||||
|
func (c *linuxContainer) doesInitProcessExist(initPid int) (bool, error) {
|
||||||
|
startTime, err := system.GetProcessStartTime(initPid)
|
||||||
|
if err != nil {
|
||||||
|
return false, newSystemErrorWithCausef(err, "getting init process %d start time", initPid)
|
||||||
|
}
|
||||||
|
if c.initProcessStartTime != startTime {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) runType() (Status, error) {
|
func (c *linuxContainer) runType() (Status, error) {
|
||||||
if c.initProcess == nil {
|
if c.initProcess == nil {
|
||||||
return Stopped, nil
|
return Stopped, nil
|
||||||
|
@ -1124,6 +1148,11 @@ func (c *linuxContainer) runType() (Status, error) {
|
||||||
}
|
}
|
||||||
return Stopped, newSystemErrorWithCausef(err, "sending signal 0 to pid %d", pid)
|
return Stopped, newSystemErrorWithCausef(err, "sending signal 0 to pid %d", pid)
|
||||||
}
|
}
|
||||||
|
// check if the process is still the original init process.
|
||||||
|
exist, err := c.doesInitProcessExist(pid)
|
||||||
|
if !exist || err != nil {
|
||||||
|
return Stopped, err
|
||||||
|
}
|
||||||
// check if the process that is running is the init process or the user's process.
|
// check if the process that is running is the init process or the user's process.
|
||||||
// this is the difference between the container Running and Created.
|
// this is the difference between the container Running and Created.
|
||||||
environ, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/environ", pid))
|
environ, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/environ", pid))
|
||||||
|
|
|
@ -218,6 +218,7 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
|
||||||
}
|
}
|
||||||
c := &linuxContainer{
|
c := &linuxContainer{
|
||||||
initProcess: r,
|
initProcess: r,
|
||||||
|
initProcessStartTime: state.InitProcessStartTime,
|
||||||
id: id,
|
id: id,
|
||||||
config: &state.Config,
|
config: &state.Config,
|
||||||
initPath: l.InitPath,
|
initPath: l.InitPath,
|
||||||
|
|
Loading…
Reference in New Issue