-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
tsh: ignore empty or non-existing config files #11495
tsh: ignore empty or non-existing config files #11495
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marcoandredinis Good catch! Have one comment.
tool/tsh/tsh.go
Outdated
confOptions, err := loadConfig(cf.HomePath) | ||
if err != nil && !trace.IsNotFound(err) { | ||
if trace.IsNotFound(err) { | ||
err = nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I wonder if it would be a little cleaner interface if we made loadConfig
return an empty config in case the config file does not exist. Then the caller won't have to worry about handling the not found error. cc @lxea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marcoandredinis Also, please include test coverage with the change. If you take my suggestion, I think you can just write a test for loadConfig
and make sure it doesn't return error if the file isn't found.
727fb99
to
df62670
Compare
Should we also get a valid config if file is empty? 🤔 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also get a valid config if file is empty?
@marcoandredinis If yaml decoder fails with empty file, I'd return an empty config in that case also, yes. Otherwise lgtm.
80f5d81
to
ade6f70
Compare
a8d5f6a
to
85cdae7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have some comments after the latest changes.
tool/tsh/tshconfig.go
Outdated
if err != nil { | ||
return nil, trace.ConvertSystemError(err) | ||
} | ||
if len(bs) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I'd use bytes.TrimSpace before comparing the length just in case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up removing the empty/only spaces checks
yaml.Unmarshal handles that just fine
We initially added the check because we were decoding using yaml.NewDecoder(configFile).Decode(&cfg)
and that requires at least one valid node: https://pkg.go.dev/gopkg.in/yaml.v2#Decoder.Decode
However, the Unmarshal is fine with empty input
tool/tsh/tshconfig.go
Outdated
cfg := TshConfig{} | ||
err = yaml.NewDecoder(configFile).Decode(&cfg) | ||
return &cfg, trace.Wrap(err) | ||
if yaml.Unmarshal(bs, &cfg); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if yaml.Unmarshal(bs, &cfg); err != nil { | |
if err := yaml.Unmarshal(bs, &cfg); err != nil { |
tool/tsh/tshconfig.go
Outdated
confPath := filepath.Join(profile.FullProfilePath(homePath), tshConfigPath) | ||
configFile, err := os.Open(confPath) | ||
func loadConfig(fullConfigPath string) (*TshConfig, error) { | ||
emptyConfig := &TshConfig{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think that usually you'd just return &TshConfig{}, nil
inline, so you don't really need additional emptyConfig
variable.
tool/tsh/tshconfig.go
Outdated
return nil, trace.ConvertSystemError(err) | ||
} | ||
defer configFile.Close() | ||
|
||
bs, err := io.ReadAll(configFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use os.ReadFile
instead of Open+ReadAll then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marcoandredinis Let's merge and backport to branch/v9 please.
If the newly created config.yaml doesn't exist we load the default values and continue the flow However, we were not resetting the `err`'s value and would have an ERROR message at the end and an invalid exit code Most of the commands would reset that variable to the output of the command's execution One of them was not: `tsh version` The version command has not return value, so the program would execute as expected until the last statement: `trace.Wrap(error)` which would re-use the `err` variable whose value is the result of the `loadConfig` method. We could clean up the `err`'s value or return no error at all and an empty config when the file doesn't exist We ended up picking the latter option as it seems cleaner ``` # before $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ERROR: open /home/marco/.tsh/config/config.yaml: no such file or directory # after $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ```
yaml.Unmarshal handles empty files just fine, no need to do prior checks for empty or space only files
bddd3e0
to
ee119d6
Compare
If the newly created config.yaml didnt exist we would load the default values and continue the flow However, we were not resetting the `err`'s value and would have an ERROR message at the end and an invalid exit code Most of the commands would reset that variable to the output of the command's execution One of them was not: `tsh version` The version command has no return value, so the program would execute as expected until the last statement: `trace.Wrap(error)` which would re-use the `err` variable whose value is the result of the `loadConfig` method. We could either reset the `err`s value inside the `PrintVersion` switch case block or reset it right after we check for `IsNotFound`. We ended up picking the first option as it seems cleaner ``` # before $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ERROR: open /home/marco/.tsh/config/config.yaml: no such file or directory # after $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ```
If the newly created config.yaml didnt exist we would load the default values and continue the flow However, we were not resetting the `err`'s value and would have an ERROR message at the end and an invalid exit code Most of the commands would reset that variable to the output of the command's execution One of them was not: `tsh version` The version command has no return value, so the program would execute as expected until the last statement: `trace.Wrap(error)` which would re-use the `err` variable whose value is the result of the `loadConfig` method. We could either reset the `err`s value inside the `PrintVersion` switch case block or reset it right after we check for `IsNotFound`. We ended up picking the first option as it seems cleaner ``` # before $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ERROR: open /home/marco/.tsh/config/config.yaml: no such file or directory # after $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ```
@marcoandredinis Looks like this needs to go to branch/v8 as well. |
@zmb3 Indeed |
If the newly created config.yaml didnt exist we would load the default values and continue the flow However, we were not resetting the `err`'s value and would have an ERROR message at the end and an invalid exit code Most of the commands would reset that variable to the output of the command's execution One of them was not: `tsh version` The version command has no return value, so the program would execute as expected until the last statement: `trace.Wrap(error)` which would re-use the `err` variable whose value is the result of the `loadConfig` method. We could either reset the `err`s value inside the `PrintVersion` switch case block or reset it right after we check for `IsNotFound`. We ended up picking the first option as it seems cleaner ``` # before $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ERROR: open /home/marco/.tsh/config/config.yaml: no such file or directory # after $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ```
* tsh: ignore empty or non-existing config files (#11495) If the newly created config.yaml didnt exist we would load the default values and continue the flow However, we were not resetting the `err`'s value and would have an ERROR message at the end and an invalid exit code Most of the commands would reset that variable to the output of the command's execution One of them was not: `tsh version` The version command has no return value, so the program would execute as expected until the last statement: `trace.Wrap(error)` which would re-use the `err` variable whose value is the result of the `loadConfig` method. We could either reset the `err`s value inside the `PrintVersion` switch case block or reset it right after we check for `IsNotFound`. We ended up picking the first option as it seems cleaner ``` # before $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ERROR: open /home/marco/.tsh/config/config.yaml: no such file or directory # after $ make full > /dev/null; build/tsh version Teleport v10.0.0-dev git:v8.0.0-alpha.1-899-g335adf1f4 go1.18 ``` * fix tsh config test (#11603) check for error when writing to a file
If the newly created config.yaml didnt exist we would load the default
values and continue the flow
However, we were not resetting the
err
's value and would have an ERRORmessage at the end and an invalid exit code
Most of the commands would reset that variable to the output of the
command's execution
One of them was not:
tsh version
The version command has no return value, so the program would execute
as expected until the last statement:
trace.Wrap(error)
which wouldre-use the
err
variable whose value is the result of theloadConfig
method.
We could either reset the
err
s value inside thePrintVersion
switchcase block or reset it right after we check for
IsNotFound
.We ended up picking the first option as it seems cleaner