Repository navigation
Pattern for defining and loading application configuration - #149
Conversation
| } | ||
|
|
||
| func Launch() { | ||
| rootCmd := createRootCmd() |
There was a problem hiding this comment.
Notice that globals and init functions are being killed off in favor of doing more work here in Launch.
|
This is what the help text looks like with this approach: |
| } | ||
|
|
||
| // LoadConfig will load the config variables into a fully initialized AppConfig struct | ||
| func (man ConfigManager) LoadConfig() AppConfig { |
There was a problem hiding this comment.
It could also be possible to add struct tags above and then use reflection to do this and AttachConfigs without requiring manual editing of these functions. (Note though that code that needs to both access the struct field tags and set the struct field values is going to end up pretty messy because of how reflect.StructField and reflect.Value behave.)
|
Without diving into the code, the CLI interface is exactly how I envision a perfect server CLI ui :) |
| ) | ||
|
|
||
| type AppConfig struct { | ||
| Mysql struct { |
There was a problem hiding this comment.
Each one of these should be their own type, and embed them in AppConfig.
It's easier to read/reason about and also work with.
There was a problem hiding this comment.
@groob You mean like
type mysqlConfig struct {
...
}
type AppConfig struct {
Mysql mysqlConfig
}
yeah?
|
@zwass I think this is going in a good direction overall. Before completing this PR, would you mind opening the package in GoDoc and seeing what the documentation looks like? It would be great if the package API only exported functions/methods which were absolutely necessary. I'd like to be able to learn how to add/remove commands to Kolide without reading the source, and that would be good for on-boarding new developers as well. |
| viper.GetString("mysql.password"), | ||
| viper.GetString("mysql.address"), | ||
| viper.GetString("mysql.database"), | ||
| ) |
There was a problem hiding this comment.
Shouldn't the config be parsed before this? And then this should use the config struct with strong types and sane defaults?
There was a problem hiding this comment.
This is old code that I haven't killed yet. We would load the config through the ConfigManager and access it with strong types from there (like https://github.com/kolide/kolide-ose/pull/149/files#diff-a4c2ccfae6e99bf0b872bdb97ae6b0d7R33).
|
I don't often see applications mixing periods and underscores so freely in CLI flags (like |
| @@ -69,4 +79,9 @@ Available Configurations: | |||
| debug (bool) (KOLIDE_LOGGING_DEBUG) | |||
| disable_banner (bool) (KOLIDE_LOGGING_DISABLE_BANNER) | |||
There was a problem hiding this comment.
Shouldn't all of this be RM'd now that the flags are being specified in help text some other way?
There was a problem hiding this comment.
Yes. There's tons of cleanup that I didn't want to do until I got the go ahead from you guys on the approach.
|
That would be easy to change if we want to replace |
|
I've seen this in multiple applications. Here's an example from prometheus IMO it's not bad. Either style is fine as long as it's consistent. |
|
Yeah, idc if we do all dots or all underscores or all dashes, but I think we should do all of one thing. |
|
All dash would be the logical choice then, since you already need the dash to specify the flag. |
|
@marpaia and @groob This has been cleaned up substantially to pretty much how I would imagine merging it. There is still much work to be done to pass the Help text: Godoc: |
|
@zwass, looking at GoDoc, it's not immediately clear what the difference/precedence of Can we get rid of InitConfig or rename it somehow? |
Is there a reason the config file is used if I didn't specify one explicitly? |
|
To your first question: Good point, let me try to clean that up. They may be able to be merged. Next question: This is behavior that I inherited from the existing config stuff. See https://github.com/kolide/kolide-ose/pull/149/files#diff-3baf47c64847a8fb8aaa8cc2e088513bR307 for the implementation. We can remove it if it does not make sense. |
|
IMO it's more confusing to have the config file loaded when flags/env variables have precedence. @marpaia thoughts? |
|
I'm with @groob on that matter, but not a strong opinion. |
|
@zwass would you mind addressing these golint comments as well. The |
|
Good catch on those. We should add |
| logrus.Fatalf("Error reading config file: %s", viper.ConfigFileUsed()) | ||
| } | ||
|
|
||
| logrus.Info("Using config file: ", viper.ConfigFileUsed()) |
There was a problem hiding this comment.
A few points here:
First, Could we switch this to the go-kit/logger? We should standardize on a logger, and IMO the go-kit logger is a bit nicer than logrus.
Second, this is still a global/implicit dependency. Just like all the other dependencies which are passed down to all the packages, the logger should be explicit. Perhaps change InitConfig to take logger as a parameter?
There was a problem hiding this comment.
Agreed on both points. We should definitely be standardizing logging throughout the app.
However, what do you think of doing these particular log lines directly to std(err|out) (viafmt)? At this point we haven't even looked at the configs for logging so it seems inappropriate to actually be initializing a logger and using that.
|
The rest LGTM! |
| prepareCmd.AddCommand(dbCmd) | ||
| rootCmd.AddCommand(prepareCmd) | ||
| } | ||
| func createPrepareCmd(confManager config.Manager) *cobra.Command { |
There was a problem hiding this comment.
SUPER nit: can we change this param to be configManager? I feel like, if we pay the price of just two extra characters, we can just use the clearer, full words. Seems like the juice is worth the proverbial squeeze.
There was a problem hiding this comment.
Yeah I'm fine with that. It's not really a great savings.
|
I didn't know you could get text based godoc! That's cool :) |
|
So the original reason why the example config was loaded was because we wanted there to be defaults which may or may not have been different than the config values required to use the development environment. For example, configuring SMTP to use MailHog and stuff. The logic implemented that IFF we can somehow determine that you're running the binary after just building from source (ie: the relative path of the example config exists), then you're PROBABLY running the dev infra and would want to load the example config, so let's just do that automatically. If we don't think it's important to do that anymore, we can remove it, but that's why it was there in the first place. |
|
There are a few places in the code where |
|
@marpaia A couple of your last comments are noticing that we are not fully taking advantage of the config struct at this point. My intention is to merge this branch as the pattern for defining/loading config, and then get to work on eliminating uses of |
This PR refactors most of the codebase to use the new config patterns implemented in #149. Now the core service keeps a copy of the KolideConfig struct, and service methods can reference the configuration in that struct when they need it. The most significant refactoring is in the sessions code, separating the business logic from the storage layer.

This provides a new pattern for defining and loading configuration for the Kolide server. With this PR, configuration is stored in the
config.KolideConfigstruct, and loaded throughconfig.Manager. Refer to the patterns inconfig/config.goandcli/prepare.goto see how configuration is defined and used.A follow-up PR will work on removing further references to
viperthroughout the codebase, instead preferring to access configuration through the strongly typedKolideConfig.