Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix check pid existence when running in different process namespace (container) #821

Merged
merged 1 commit into from
Feb 8, 2020

Conversation

i-prudnikov
Copy link
Contributor

This fix is to address issue mentioned in #713, originally comes from influxdata/telegraf#6813

@shirou
Copy link
Owner

shirou commented Jan 18, 2020

Indeed. It could break cgroup independency, but if a user does not want to allow a process can watch a process existance out side of a container, simply does not add environment variable. So I agree to this PR.

so basically I agree to this great PR, but could you go fmt please?

@@ -5,6 +5,7 @@ package process
import (
"context"
"fmt"
"github.com/shirou/gopsutil/internal/common"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow our convention to separate stdlib and 3rd-party packages in import statements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, gofmt was surprisingly switched off :)

file, err := os.Open(common.HostProc(strconv.Itoa(int(pid))))
defer file.Close()
if err!=nil{return false, err} else{return true, nil}
}else{ //Assume that we are in the same process namespace, try to signal process
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless else as we always return in the if.

Copy link
Contributor Author

@i-prudnikov i-prudnikov Jan 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and below, just restructured this part taking into consideration current and all of the comments below.

case syscall.EPERM:
return true, nil

if ! strings.HasPrefix(common.HostProc(),"/proc") { //Means that proc is mounted not to /proc, and we highly
Copy link
Collaborator

@Lomanic Lomanic Jan 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is called on freebsd openbsd darwin where there is no procfs, could lead to downstream breakage if users blindly set the HOST_PROC variable on every OS. Probably check for common.HostProc() existence instead/also.

if ! strings.HasPrefix(common.HostProc(),"/proc") { //Means that proc is mounted not to /proc, and we highly
// likely running inside container with a different process namespace (by default), so we check pid existence
// based on /<HOST_PROC>/proc/<PID> folder
file, err := os.Open(common.HostProc(strconv.Itoa(int(pid))))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use os.Stat instead as in this commit 2583438

return true, nil

if ! strings.HasPrefix(common.HostProc(),"/proc") { //Means that proc is mounted not to /proc, and we highly
// likely running inside container with a different process namespace (by default), so we check pid existence
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, all your comments assume we're running on Linux, which is confusing because this code is common to all POSIX platforms.

@i-prudnikov i-prudnikov force-pushed the process_check_pid_exnistense_fix branch from 4c34bd1 to cf14906 Compare January 20, 2020 15:38
@i-prudnikov
Copy link
Contributor Author

i-prudnikov commented Jan 20, 2020

Overall, I followed this logic:

  1. If /<HOST_PROC>/proc or /proc exist, then PID existence is checked via existence of folder in proc filesystem
  2. Otherwise PID existence is checked by signalling.

defer file.Close()
if err!=nil{return false, err} else{return true, nil}
}else{ //Assume that we are in the same process namespace, try to signal process
if _, err := os.Stat(common.HostProc()); err == nil { //Means that proc filesystem exist
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it is 2 calls to os.Stat, can be reduced to 1 if we cache somewhere in global var the result of this line.
@Lomanic, @shirou could you please advise the right place for that?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These os.Stat target are different and second one is a fallback. so we can not merge.

Copy link
Contributor Author

@i-prudnikov i-prudnikov Jan 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, they are. But maybe my point is not clear. What I'm trying to say that the os.Stat(common.HostProc()) call is useless to be made every time when we check pid existence, this is something that could be checked once at startup or init. Possible use case here is when you have an array of PIDs (let's call it pidArray) and you check every entry in cycle for PID existence. In this case you have n useless os.Stat calls, where n=len(pidArray).

@shirou
Copy link
Owner

shirou commented Jan 26, 2020

Thank you @Lomanic and @i-prudnikov . LGTM. If you don't have a comment, please merge this PR.

@Lomanic
Copy link
Collaborator

Lomanic commented Jan 26, 2020

@i-prudnikov please squash your commits as to preserve lines history. Or @shirou please enable this option for merges. Thanks.

@shirou
Copy link
Owner

shirou commented Jan 27, 2020

Oh, roger. I have enabled squash merge!

@i-prudnikov i-prudnikov force-pushed the process_check_pid_exnistense_fix branch from cf14906 to 8dec3d8 Compare January 27, 2020 08:58
@i-prudnikov
Copy link
Contributor Author

@shirou, @Lomanic commits are squashed, thank you for review.

@i-prudnikov i-prudnikov mentioned this pull request Feb 5, 2020
@shirou
Copy link
Owner

shirou commented Feb 8, 2020

LGTM now. Thank you for your contribution!

@shirou shirou merged commit a9d510e into shirou:master Feb 8, 2020
@Lomanic
Copy link
Collaborator

Lomanic commented Feb 13, 2020

This shouldn't have been merged as now the following test is failing:

--- FAIL: Test_IsRunning (1.00s)
    process_test.go:620: IsRunning error: open /proc/11200/stat: no such file or directory

A non-running process should not return an error.

We really need a better CI (#734) to catch this kind of regressions.

@i-prudnikov
Copy link
Contributor Author

@Lomanic , could you please provide the commit SHA from which you run the failed test. I'll try to investigate what goes wrong. I see that I have mismatched process_test.go file in my source branch.

@i-prudnikov
Copy link
Contributor Author

@Lomanic, I've run test against master branch, the root case is the returned error from PidExistsWithContext function, that should be nil, in case process is not found. The fix is a simple as:

_, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
if e, ok := err.(*os.PathError); ok && e.Err.(syscall.Errno) == syscall.ENOENT {
	return err == nil, nil
}
return err == nil, err

I've opened a new merge request for that fix: #840

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants