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

Do not wrap errors from filepath / os as they are already wrapped. #109

Merged
merged 1 commit into from
Apr 7, 2022

Conversation

manugupt1
Copy link
Contributor

@manugupt1 manugupt1 commented Apr 6, 2022

While trying to import MountedFast into k8s to detect mount points
using openat2, several tests failed because they rely on
os.IsErrNotExist / os.IsPermission which do not actually test the
underlying error.

For a non-existent path, if we return the bare error, this problem
is solved. I tested for the following cases to ensure that
backward compatibility is not broken:

fmt.Println(os.IsNotExist(err)) returns false
fmt.Println(os.IsNotExist(&os.PathError{
		Op:   "lstat",
		Path: "somepath",
		Err:  err,
})) returns false

fmt.Println(os.IsNotExist(fmt.Errorf("unable: %w", err))) returns false
fmt.Println(errors.Is(fmt.Errorf("unable: %w", err), os.ErrNotExist))
returns true.
```

cc @kolyshkin @thaJeztah 

@manugupt1 manugupt1 force-pushed the propagate-bare-errors branch from 13957d6 to b521653 Compare April 6, 2022 00:06
@manugupt1 manugupt1 marked this pull request as ready for review April 6, 2022 00:07
@manugupt1 manugupt1 changed the title Send Unix errors without wrapping them or casting them. Send Unix errors without wrapping them or wrapping them. Apr 6, 2022
@thaJeztah
Copy link
Member

Hmm bit on the fence on this one; we'll lose some context on the errors, and os.IsNotExist() generally should only be used when directly interacting with the os package; https://pkg.go.dev/os#IsNotExist

This function predates errors.Is. It only supports errors returned by the os package. New code should use errors.Is(err, fs.ErrNotExist).

@manugupt1
Copy link
Contributor Author

Hmm bit on the fence on this one; we'll lose some context on the errors, and os.IsNotExist() generally should only be used when directly interacting with the os package; https://pkg.go.dev/os#IsNotExist

This function predates errors.Is. It only supports errors returned by the os package. New code should use errors.Is(err, fs.ErrNotExist).

Yep! This is because there is a lot of old code that relies os.ErrNotExist in k8s (see: kubernetes/kubernetes@49f76c3) and it is proving incredibly hard to unwrap them and maintain compatibility. os.IsNotExist is not the only error; there is os.IsPermission that it relies on.

Comment on lines -36 to +41
return "", fmt.Errorf("unable to get absolute path for %q: %w", path, err)
return "", err
}
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
return "", fmt.Errorf("failed to canonicalise path for %q: %w", path, err)
return "", err
}
if _, err := os.Stat(realPath); err != nil {
return "", fmt.Errorf("failed to stat target of %q: %w", path, err)
return "", err
Copy link
Collaborator

Choose a reason for hiding this comment

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

This part of patch might actually make sense (since the errors from os.Stat and filepath are probably already wrapped).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, os.IsNotExist() does not work for errors wrapped using %w (see https://go.dev/play/p/RcpXLGqwO9l), and since

  • both filepath.EvalSymlinks and os.Stat already contain path in their error message;
  • filepath.Abs can only return an error from os.Getwd() which is already descriptive enough,
    this part of patch does makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

Also, os.IsNotExist() does not work for errors wrapped using %w (see https://go.dev/play/p/RcpXLGqwO9l), and since

The reverse is also true for some errors unfortunately (and based on the discussion in golang/go#39155, I doubt that'll change)

@kolyshkin
Copy link
Collaborator

@manugupt1 I do not understand the need for change; os.IsNotExist() should work just fine.

Please see the following example that works as expected: https://go.dev/play/p/kAy9rCXZaW4

If something is not working like you think it should, can you please provide the example similar to mine?

@kolyshkin
Copy link
Collaborator

@manugupt1 I do not understand the need for change

I stand corrected -- part of this PR actually makes sense (see https://github.com/moby/sys/pull/109#discussion_r843415781https://github.com/moby/sys/pull/109#discussion_r843415781)

@manugupt1
Copy link
Contributor Author

@manugupt1 I do not understand the need for change; os.IsNotExist() should work just fine.

Please see the following example that works as expected: https://go.dev/play/p/kAy9rCXZaW4

If something is not working like you think it should, can you please provide the example similar to mine?

Hi Kir,
I had the following examples when I was testing: Wrapping with &os.PathError{err: Err} also returns false

https://go.dev/play/p/n156HDTShUu

@kolyshkin
Copy link
Collaborator

kolyshkin commented Apr 6, 2022 via email

@kolyshkin
Copy link
Collaborator

@manugupt1 can you adopt the commit accordingly (i.e. only leave the part that patches normalizePath, and drop the part that wraps bare unix errors into os.PathError)?

@kolyshkin
Copy link
Collaborator

@manugupt1 can you adopt the commit accordingly (i.e. only leave the part that patches normalizePath, and drop the part that wraps bare unix errors into os.PathError)?

and fix the commit description accordingly (saying that errors from os or filepath do not need to be wrapped).

@manugupt1 manugupt1 force-pushed the propagate-bare-errors branch 3 times, most recently from 233b438 to 9edc129 Compare April 7, 2022 00:21
@manugupt1 manugupt1 changed the title Send Unix errors without wrapping them or wrapping them. Do not wrap errors from filepath and stat as they are already wrapped. Apr 7, 2022
Since errors from filepath/ost are already wrapped, they
do not need to be wrapped again. Wrapping them again will
cause os.IsErrNotExist(err) to return false while some providers
may want it to be true.

Signed-off-by: Manu Gupta <manugupt1@gmail.com>
@manugupt1 manugupt1 force-pushed the propagate-bare-errors branch from 9edc129 to 4ac34a1 Compare April 7, 2022 00:27
@manugupt1 manugupt1 changed the title Do not wrap errors from filepath and stat as they are already wrapped. Do not wrap errors from filepath / os as they are already wrapped. Apr 7, 2022
Copy link
Collaborator

@kolyshkin kolyshkin left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@thaJeztah thaJeztah merged commit 925ece2 into moby:main Apr 7, 2022
@manugupt1 manugupt1 deleted the propagate-bare-errors branch April 7, 2022 14:55
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