fix path error in systemd when stopped

When we use cgroup with systemd driver, the cgroup path will be auto removed
by systemd when all processes exited. So we should check cgroup path exists
when we access the cgroup path, for example in `kill/ps`, or else we will
got an error.

Signed-off-by: lifubang <lifubang@acmcoder.com>
This commit is contained in:
lifubang 2020-04-23 21:33:47 +08:00
parent dbe5acade3
commit 9087f2e827
8 changed files with 70 additions and 8 deletions

View File

@ -47,6 +47,9 @@ type Manager interface {
// GetFreezerState retrieves the current FreezerState of the cgroup.
GetFreezerState() (configs.FreezerState, error)
// Whether the cgroup path exists or not
Exists() bool
}
type NotFoundError struct {

View File

@ -392,3 +392,7 @@ func (m *manager) GetFreezerState() (configs.FreezerState, error) {
}
return freezer.(*FreezerGroup).GetState(dir)
}
func (m *manager) Exists() bool {
return cgroups.PathExists(m.paths["devices"])
}

View File

@ -262,3 +262,7 @@ func (m *manager) GetCgroups() (*configs.Cgroup, error) {
func (m *manager) GetFreezerState() (configs.FreezerState, error) {
return getFreezer(m.dirPath)
}
func (m *manager) Exists() bool {
return cgroups.PathExists(m.dirPath)
}

View File

@ -65,3 +65,7 @@ func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
func (m *Manager) GetCgroups() (*configs.Cgroup, error) {
return nil, errors.New("Systemd not supported")
}
func (m *Manager) Exists() bool {
return false
}

View File

@ -481,3 +481,7 @@ func (m *legacyManager) GetFreezerState() (configs.FreezerState, error) {
}
return freezer.(*fs.FreezerGroup).GetState(path)
}
func (m *legacyManager) Exists() bool {
return cgroups.PathExists(m.paths["devices"])
}

View File

@ -370,3 +370,7 @@ func (m *unifiedManager) GetFreezerState() (configs.FreezerState, error) {
}
return fsMgr.GetFreezerState()
}
func (m *unifiedManager) Exists() bool {
return cgroups.PathExists(m.path)
}

View File

@ -169,7 +169,17 @@ func (c *linuxContainer) OCIState() (*specs.State, error) {
}
func (c *linuxContainer) Processes() ([]int, error) {
pids, err := c.cgroupManager.GetAllPids()
var pids []int
status, err := c.currentStatus()
if err != nil {
return pids, err
}
// for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited
if status == Stopped && !c.cgroupManager.Exists() {
return pids, nil
}
pids, err = c.cgroupManager.GetAllPids()
if err != nil {
return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups")
}
@ -385,13 +395,17 @@ func (c *linuxContainer) start(process *Process) error {
func (c *linuxContainer) Signal(s os.Signal, all bool) error {
c.m.Lock()
defer c.m.Unlock()
if all {
return signalAllProcesses(c.cgroupManager, s)
}
status, err := c.currentStatus()
if err != nil {
return err
}
if all {
// for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited
if status == Stopped && !c.cgroupManager.Exists() {
return nil
}
return signalAllProcesses(c.cgroupManager, s)
}
// to avoid a PID reuse attack
if status == Running || status == Created || status == Paused {
if err := c.initProcess.signal(s); err != nil {

View File

@ -50,6 +50,15 @@ func (m *mockCgroupManager) Destroy() error {
return nil
}
func (m *mockCgroupManager) Exists() bool {
paths := m.GetPaths()
if paths != nil {
_, err := os.Lstat(paths["devices"])
return err == nil
}
return false
}
func (m *mockCgroupManager) GetPaths() map[string]string {
return m.paths
}
@ -134,11 +143,27 @@ func (m *mockProcess) forwardChildLogs() {
}
func TestGetContainerPids(t *testing.T) {
container := &linuxContainer{
id: "myid",
config: &configs.Config{},
cgroupManager: &mockCgroupManager{allPids: []int{1, 2, 3}},
pid := 1
stat, err := system.Stat(pid)
if err != nil {
t.Fatalf("can't stat pid %d, got %v", pid, err)
}
container := &linuxContainer{
id: "myid",
config: &configs.Config{},
cgroupManager: &mockCgroupManager{
allPids: []int{1, 2, 3},
paths: map[string]string{
"device": "/proc/self/cgroups",
},
},
initProcess: &mockProcess{
_pid: 1,
started: 10,
},
initProcessStartTime: stat.StartTime,
}
container.state = &runningState{c: container}
pids, err := container.Processes()
if err != nil {
t.Fatal(err)