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

cli/config: improve handling of errors #5077

Merged
merged 4 commits into from
May 22, 2024

Conversation

thaJeztah
Copy link
Member

Improving some parts of how we handle failures when loading the CLI configuration file. This relates to #5075, but does not yet fix that issue (only handling some additional errors);

Changes in this PR should not likely cause a change in behavior (so could be included in a patch release); follow-up changes are still needed to handle various scenarios where we should hard-fail, but there's many different related code-paths, so this still needs work.

cli/config: Load(): improve GoDoc

cli/config: add test for dangling symlink for config-file

This may need further discussion, but we currently handle dangling
symlinks gracefully, so let's add a test for this, and verify that
we don't replace symlinks with a file.

cli/config: TestLoadDefaultConfigFile: check that no warnings are printed

Loading the config should print no warnings on a successful load.

cli/config: do not discard permission errors when loading config-file

When attempting to load a config-file that exists, but is not accessible for
the current user, we should not discard the error.

This patch makes sure that the error is returned by Load(), but does not yet
change LoadDefaultConfigFile, as this requires a change in signature.

- Description for the changelog

Print a warning when the CLI does not have permissions to read the configuration file.

- A picture of a cute animal (not mandatory but encouraged)

@thaJeztah
Copy link
Member Author

Ah 🙈 probably testing won't work if it's running as root;

59.75 === FAIL: cli/config TestLoadNoPermissions (0.00s)
59.75     config_test.go:79: assertion failed: error is nil, not "permission denied" (os.ErrPermission)
59.75 
59.75 === FAIL: cli/config TestLoadDefaultConfigFile/permission_error (0.00s)
59.75     config_test.go:377: assertion failed: string "" does not contain "WARNING:"
59.75     config_test.go:378: assertion failed: string "" does not contain "permission denied"

Copy link
Contributor

@vvoland vvoland left a comment

Choose a reason for hiding this comment

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

LGTM (once CI is green)

Comment on lines +75 to +77
if runtime.GOOS != "windows" {
skip.If(t, os.Getuid() == 0, "cannot test permission denied when running as root")
}
Copy link
Member Author

Choose a reason for hiding this comment

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

I tried if I could make the tests run as non-root, but ran into some issues, so for now, skipping this tests when running as root.

@thaJeztah thaJeztah requested a review from krissetto May 21, 2024 11:56
Copy link
Contributor

@krissetto krissetto left a comment

Choose a reason for hiding this comment

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

overal LGTM, with some godoc nits/questions

@@ -84,8 +84,14 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
return &configFile, err
}

// Load reads the configuration files in the given directory, and sets up
// the auth config information and returns values.
// Load reads the configuration file ([ConfigFileName]) from the given directory.
Copy link
Contributor

Choose a reason for hiding this comment

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

what is ([ConfigFileName]) here?

Copy link
Member Author

Choose a reason for hiding this comment

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

They're "doc links"; if you use brackets and put a reference to a type, then GoDoc renders them as links.

You can test those using pkgsite (go install golang.org/x/pkgsite/cmd/pkgsite@latest), and then browse the docs (it's a bit fiddly on the CLI because of go modules, so I just ran it in a container);

Screenshot 2024-05-21 at 16 16 32 Screenshot 2024-05-21 at 16 16 52

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, good to know! I didn't think that having just the type name would be enough for the linking to occur

// Load reads the configuration files in the given directory, and sets up
// the auth config information and returns values.
// Load reads the configuration file ([ConfigFileName]) from the given directory.
// If no directory is given, it uses the default [Dir]. A [configfile.ConfigFile]
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: [*configfile.ConfigFile] here since it's a pointer?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh! Looks like that works as well; I thought GoDoc links wouldn't accept that (so requiring to manually construct a link), but it looks like it does;

Screenshot 2024-05-22 at 10 20 03

// than it doesn't exist then stop
return configFile, nil
// Any other error happening when failing to read the file must be returned.
return configFile, errors.Wrap(err, "loading config file")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe errors.Wrapf(err, "loading config file: %s: ", filename) like below so the errors have a consistent format?

Copy link
Member Author

@thaJeztah thaJeztah May 21, 2024

Choose a reason for hiding this comment

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

I left that out, because os.Open returns a os.PathError / fs.PathError; https://pkg.go.dev/os#PathError and those already include the path, which would be open /no/such/file: no such file or directory, so manually adding the filename would now have the filename in the error twice.

}
return configFile, err
}

// LoadDefaultConfigFile attempts to load the default config file and returns
// an initialized ConfigFile struct if none is found.
// an initialized ConfigFile struct if none is found or when failing to load
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure about godoc best practices when returning pointers to structs, should we specify that here as well or only in the function signature?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I left it out for now; I think we should consider deprecating this function, or at least provide an alternative that does return the error.

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried to slightly rephrase the GoDoc to make it more clear that it returns a reference, and that it initialises a default struct if it fails to load / find a config-file.

@codecov-commenter
Copy link

codecov-commenter commented May 22, 2024

Codecov Report

Attention: Patch coverage is 66.66667% with 1 lines in your changes are missing coverage. Please review.

Project coverage is 61.34%. Comparing base (57a1180) to head (c102e29).

Current head c102e29 differs from pull request most recent head dc75e9e

Please upload reports for the commit dc75e9e to get more accurate results.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5077      +/-   ##
==========================================
+ Coverage   61.32%   61.34%   +0.02%     
==========================================
  Files         298      298              
  Lines       20706    20706              
==========================================
+ Hits        12698    12703       +5     
+ Misses       7106     7103       -3     
+ Partials      902      900       -2     

This may need further discussion, but we currently handle dangling
symlinks gracefully, so let's add a test for this, and verify that
we don't replace symlinks with a file.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
…nted

Loading the config should print no warnings on a successful load.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
When attempting to load a config-file that exists, but is not accessible for
the current user, we should not discard the error.

This patch makes sure that the error is returned by Load(), but does not yet
change LoadDefaultConfigFile, as this requires a change in signature.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
@thaJeztah
Copy link
Member Author

@krissetto I made some changes; PTAL if it LGTY

@krissetto
Copy link
Contributor

@krissetto I made some changes; PTAL if it LGTY

looking good @thaJeztah 😎

@thaJeztah
Copy link
Member Author

Let me bring this one in; I'll try to spend some time on fixing the actual handling related to #5075, but taking it small steps at a time.

@thaJeztah thaJeztah merged commit 421e3b5 into docker:master May 22, 2024
88 checks passed
@thaJeztah thaJeztah deleted the config_error_handling branch May 22, 2024 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants