Pattern for defining and loading application configuration (#149)

This provides a new pattern for defining and loading configuration for the Kolide server. With this PR, configuration is stored in the `config.KolideConfig` struct, and loaded through `config.Manager`. Refer to the patterns in `config/config.go` and `cli/prepare.go` to see how configuration is defined and used.

A follow-up PR will work on removing further references to `viper` throughout the codebase, instead preferring to access configuration through the strongly typed `KolideConfig`.
This commit is contained in:
Zachary Wasserman 2016-09-12 10:26:56 -07:00 committed by GitHub
parent 370cc4efa8
commit 6cb05a58e6
6 changed files with 502 additions and 255 deletions

38
cli/config_dump.go Normal file
View file

@ -0,0 +1,38 @@
package cli
import (
"fmt"
"github.com/Sirupsen/logrus"
"github.com/kolide/kolide-ose/config"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)
func createConfigDumpCmd(configManager config.Manager) *cobra.Command {
var configDumpCmd = &cobra.Command{
Use: "config_dump",
Short: "Dump the parsed configuration in yaml format",
Long: `
Dump the parsed configuration in yaml format.
Kolide retrieves configuration options from many locations, and it can be
useful to see the result of merging those configs.
The following precedence is used when reading configs:
1. CLI flags
2. Environment Variables
3. Config File
4. Default Values
`,
Run: func(cmd *cobra.Command, args []string) {
buf, err := yaml.Marshal(configManager.LoadConfig())
if err != nil {
logrus.Fatal("Error marshalling config to yaml")
}
fmt.Println(string(buf))
}}
return configDumpCmd
}

View file

@ -4,81 +4,87 @@ import (
"fmt"
"github.com/Sirupsen/logrus"
"github.com/kolide/kolide-ose/config"
"github.com/kolide/kolide-ose/datastore"
"github.com/kolide/kolide-ose/kolide"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init() {
prepareCmd.AddCommand(dbCmd)
rootCmd.AddCommand(prepareCmd)
rootCmd.AddCommand(testDataCmd)
}
func createPrepareCmd(configManager config.Manager) *cobra.Command {
var prepareCmd = &cobra.Command{
Use: "prepare",
Short: "Subcommands for initializing kolide infrastructure",
Long: `
var prepareCmd = &cobra.Command{
Use: "prepare",
Short: "Subcommands for initializing kolide infrastructure",
Long: `
Subcommands for initializing kolide infrastructure
To setup kolide infrastructure, use one of the available commands.
`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
var dbCmd = &cobra.Command{
Use: "db",
Short: "Given correct database configurations, prepare the databases for use",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
connString := fmt.Sprintf(
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
viper.GetString("mysql.username"),
viper.GetString("mysql.password"),
viper.GetString("mysql.address"),
viper.GetString("mysql.database"),
)
ds, err := datastore.New("gorm-mysql", connString)
if err != nil {
logrus.WithError(err).Fatal("error creating db connection")
}
if err := ds.Drop(); err != nil {
logrus.WithError(err).Fatal("error dropping db tables")
}
if err := ds.Migrate(); err != nil {
logrus.WithError(err).Fatal("error setting up db schema")
}
},
}
var testDataCmd = &cobra.Command{
Use: "test-data",
Short: "Generate test data",
Long: ``,
Run: func(cmd *cobra.Command, arg []string) {
connString := fmt.Sprintf(
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
viper.GetString("mysql.username"),
viper.GetString("mysql.password"),
viper.GetString("mysql.address"),
viper.GetString("mysql.database"),
)
ds, err := datastore.New("gorm-mysql", connString)
if err != nil {
logrus.WithError(err).Fatal("error creating db connection")
}
admin, err := kolide.NewUser("admin", "admin", "admin@kolide.co", true, false)
if err != nil {
logrus.WithError(err).Fatal("Could not create new user object")
}
_, err = ds.NewUser(admin)
if err != nil {
logrus.WithError(err).Fatal("Could not create new user in the database")
}
},
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
var dbCmd = &cobra.Command{
Use: "db",
Short: "Given correct database configurations, prepare the databases for use",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
config := configManager.LoadConfig()
connString := fmt.Sprintf(
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
config.Mysql.Username,
config.Mysql.Password,
config.Mysql.Address,
config.Mysql.Database,
)
ds, err := datastore.New("gorm-mysql", connString)
if err != nil {
logrus.WithError(err).Fatal("error creating db connection")
}
if err := ds.Drop(); err != nil {
logrus.WithError(err).Fatal("error dropping db tables")
}
if err := ds.Migrate(); err != nil {
logrus.WithError(err).Fatal("error setting up db schema")
}
},
}
prepareCmd.AddCommand(dbCmd)
var testDataCmd = &cobra.Command{
Use: "test-data",
Short: "Generate test data",
Long: ``,
Run: func(cmd *cobra.Command, arg []string) {
config := configManager.LoadConfig()
connString := fmt.Sprintf(
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
config.Mysql.Username,
config.Mysql.Password,
config.Mysql.Address,
config.Mysql.Database,
)
ds, err := datastore.New("gorm-mysql", connString)
if err != nil {
logrus.WithError(err).Fatal("error creating db connection")
}
admin, err := kolide.NewUser("admin", "admin", "admin@kolide.co", true, false)
if err != nil {
logrus.WithError(err).Fatal("Could not create new user object")
}
_, err = ds.NewUser(admin)
if err != nil {
logrus.WithError(err).Fatal("Could not create new user in the database")
}
},
}
prepareCmd.AddCommand(testDataCmd)
return prepareCmd
}

View file

@ -8,22 +8,28 @@ import (
"github.com/spf13/cobra"
)
func init() {
rootCmd.PersistentFlags().StringVar(&config.File, "config", "", "Path to a configuration file")
}
// Launch is the entrypoint that sets up and runs the Kolide commands.
func Launch() {
rootCmd := createRootCmd()
configManager := config.NewManager(rootCmd)
rootCmd.AddCommand(createPrepareCmd(configManager))
rootCmd.AddCommand(createServeCmd(configManager))
rootCmd.AddCommand(createConfigDumpCmd(configManager))
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
// RootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "kolide",
Short: "osquery management and orchestration",
Long: `
func createRootCmd() *cobra.Command {
// RootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "kolide",
Short: "osquery management and orchestration",
Long: `
osquery management and orchestration
Configurable Options:
@ -31,42 +37,10 @@ Configurable Options:
Options may be supplied in a yaml configuration file or via environment
variables. You only need to define the configuration values for which you
wish to override the default value.
Available Configurations:
mysql:
address (string) (KOLIDE_MYSQL_ADDRESS)
username (string) (KOLIDE_MYSQL_USERNAME)
password (string) (KOLIDE_MYSQL_PASSWORD)
database (string) (KOLIDE_MYSQL_DATABASE)
server:
address (string) (KOLIDE_SERVER_ADDRESS)
cert (string) (KOLIDE_SERVER_CERT)
key (string) (KOLIDE_SERVER_KEY)
auth:
jwt_key (string) (KOLIDE_AUTH_JWT_KEY)
salt_key_size (int) (KOLIDE_AUTH_SALT_KEY_SIZE)
bcrypt_cost (int) (KOLIDE_AUTH_BCRYPT_COST)
app:
web_address (string) (KOLIDE_APP_WEB_ADDRESS)
smtp:
server (string) (KOLIDE_SMTP_SERVER)
username (string) (KOLIDE_SMTP_USERNAME)
password (string) (KOLIDE_SMTP_PASSWORD)
pool_connections (int) (KOLIDE_SMTP_POOL_CONNECTIONS)
token_key_size (int) (KOLIDE_SMTP_TOKEN_KEY_SIZE)
session:
key_size (int) (KOLIDE_SESSION_KEY_SIZE)
expiration_seconds (float64) (KOLIDE_SESSION_EXPIRATION_SECONDS)
cookie_name (string) (KOLIDE_SESSION_COOKIE_NAME)
osquery:
enroll_secret (string) (KOLIDE_OSQUERY_ENROLL_SECRET)
node_key_size (int) (KOLIDE_OSQUERY_NODE_KEY_SIZE)
status_log_file (string) (KOLIDE_OSQUERY_STATUS_LOG_FILE)
result_log_file (string) (KOLIDE_OSQUERY_RESULT_LOG_FILE)
label_up_interval (int) (KOLIDE_OSQUERY_LABEL_UP_INTERVAL)
logging:
debug (bool) (KOLIDE_LOGGING_DEBUG)
disable_banner (bool) (KOLIDE_LOGGING_DISABLE_BANNER)
`,
}
rootCmd.PersistentFlags().String("config", "", "Path to a configuration file")
return rootCmd
}

View file

@ -9,6 +9,7 @@ import (
"syscall"
kitlog "github.com/go-kit/kit/log"
"github.com/kolide/kolide-ose/config"
"github.com/kolide/kolide-ose/datastore"
"github.com/kolide/kolide-ose/kolide"
"github.com/kolide/kolide-ose/server"
@ -16,14 +17,11 @@ import (
"golang.org/x/net/context"
)
func init() {
rootCmd.AddCommand(serveCmd)
}
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Launch the kolide server",
Long: `
func createServeCmd(configManager config.Manager) *cobra.Command {
return &cobra.Command{
Use: "serve",
Short: "Launch the kolide server",
Long: `
Launch the kolide server
Use kolide serve to run the main HTTPS server. The Kolide server bundles
@ -31,72 +29,74 @@ together all static assets and dependent libraries into a statically linked go
binary (which you're executing right now). Use the options below to customize
the way that the kolide server works.
`,
Run: func(cmd *cobra.Command, args []string) {
var (
httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
ctx = context.Background()
logger kitlog.Logger
)
flag.Parse()
logger = kitlog.NewLogfmtLogger(os.Stderr)
logger = kitlog.NewContext(logger).With("ts", kitlog.DefaultTimestampUTC)
ds, _ := datastore.New("inmem", "")
svcConfig := server.ServiceConfig{
Datastore: ds,
SessionCookieName: "KolideSession",
BcryptCost: 12,
SaltKeySize: 24,
JWTKey: "foobar",
}
svcLogger := kitlog.NewContext(logger).With("component", "service")
var svc kolide.Service
{ // temp create an admin user
svc, _ = server.NewService(svcConfig)
Run: func(cmd *cobra.Command, args []string) {
var (
name = "admin"
username = "admin"
password = "secret"
email = "admin@kolide.co"
enabled = true
isAdmin = true
httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
ctx = context.Background()
logger kitlog.Logger
)
admin := kolide.UserPayload{
Name: &name,
Username: &username,
Password: &password,
Email: &email,
Enabled: &enabled,
Admin: &isAdmin,
flag.Parse()
logger = kitlog.NewLogfmtLogger(os.Stderr)
logger = kitlog.NewContext(logger).With("ts", kitlog.DefaultTimestampUTC)
ds, _ := datastore.New("inmem", "")
svcConfig := server.ServiceConfig{
Datastore: ds,
SessionCookieName: "KolideSession",
BcryptCost: 12,
SaltKeySize: 24,
JWTKey: "foobar",
}
_, err := svc.NewUser(ctx, admin)
if err != nil {
logger.Log("err", err)
os.Exit(1)
svcLogger := kitlog.NewContext(logger).With("component", "service")
var svc kolide.Service
{ // temp create an admin user
svc, _ = server.NewService(svcConfig)
svc, _ = server.NewService(svcConfig)
var (
name = "admin"
username = "admin"
password = "secret"
email = "admin@kolide.co"
enabled = true
isAdmin = true
)
admin := kolide.UserPayload{
Name: &name,
Username: &username,
Password: &password,
Email: &email,
Enabled: &enabled,
Admin: &isAdmin,
}
_, err := svc.NewUser(ctx, admin)
if err != nil {
logger.Log("err", err)
os.Exit(1)
}
svc = server.NewLoggingService(svc, svcLogger)
}
svc = server.NewLoggingService(svc, svcLogger)
}
httpLogger := kitlog.NewContext(logger).With("component", "http")
httpLogger := kitlog.NewContext(logger).With("component", "http")
apiHandler := server.MakeHandler(ctx, svc, svcConfig.JWTKey, ds, httpLogger)
http.Handle("/api/", accessControl(apiHandler))
http.Handle("/assets/", server.ServeStaticAssets("/assets/"))
http.Handle("/", server.ServeFrontend())
apiHandler := server.MakeHandler(ctx, svc, svcConfig.JWTKey, ds, httpLogger)
http.Handle("/api/", accessControl(apiHandler))
http.Handle("/assets/", server.ServeStaticAssets("/assets/"))
http.Handle("/", server.ServeFrontend())
errs := make(chan error, 2)
go func() {
logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
errs <- http.ListenAndServe(*httpAddr, nil)
}()
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
errs := make(chan error, 2)
go func() {
logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
errs <- http.ListenAndServe(*httpAddr, nil)
}()
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
logger.Log("terminated", <-errs)
},
logger.Log("terminated", <-errs)
},
}
}
// cors headers

View file

@ -1,100 +1,328 @@
package config
import (
"fmt"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/spf13/cast"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
// File may or may not contain the path to the config file
File string
const (
envPrefix = "KOLIDE"
)
func init() {
cobra.OnInitialize(initConfig)
// MysqlConfig defines configs related to MySQL
type MysqlConfig struct {
Address string
Username string
Password string
Database string
}
// Due to a deficiency in viper (https://github.com/spf13/viper/issues/71), one
// can not set the default values of nested config elements. For example, if the
// "mysql" section of the config allows a user to define "username", "password",
// and "database", but the only wants to override the default for "username".
// they should be able to create a config which looks like:
//
// mysql:
// username: foobar
//
// In viper, that would nullify the default values of all other config keys in
// the mysql section ("mysql.*"). To get around this, instead of using the
// provided API for setting default values, after we've read the config and env,
// we manually check to see if the value has been set and, if it hasn't, we set
// it manually.
func setDefaultConfigValue(key string, value interface{}) {
if viper.Get(key) == nil {
viper.Set(key, value)
// ServerConfig defines configs related to the Kolide server
type ServerConfig struct {
Address string
Cert string
Key string
}
// AuthConfig defines configs related to user authorization
type AuthConfig struct {
JwtKey string
BcryptCost int
SaltKeySize int
}
// AppConfig defines configs related to HTTP
type AppConfig struct {
WebAddress string
}
// SMTPConfig defines configs related to SMTP email
type SMTPConfig struct {
Server string
Username string
Password string
PoolConnections int
TokenKeySize int
}
// SessionConfig defines configs related to user sessions
type SessionConfig struct {
KeySize int
ExpirationSeconds int
CookieName string
}
// OsqueryConfig defines configs related to osquery
type OsqueryConfig struct {
EnrollSecret string
NodeKeySize int
StatusLogFile string
ResultLogFile string
}
// LoggingConfig defines configs related to logging
type LoggingConfig struct {
Debug bool
DisableBanner bool
}
// KolideConfig stores the application configuration. Each subcategory is
// broken up into it's own struct, defined above. When editing any of these
// structs, Manager.addConfigs and Manager.LoadConfig should be
// updated to set and retrieve the configurations as appropriate.
type KolideConfig struct {
Mysql MysqlConfig
Server ServerConfig
Auth AuthConfig
App AppConfig
SMTP SMTPConfig
Session SessionConfig
Osquery OsqueryConfig
Logging LoggingConfig
}
// addConfigs adds the configuration keys and default values that will be
// filled into the KolideConfig struct
func (man Manager) addConfigs() {
// MySQL
man.addConfigString("mysql.address", "localhost:3306")
man.addConfigString("mysql.username", "kolide")
man.addConfigString("mysql.password", "kolide")
man.addConfigString("mysql.database", "kolide")
// Server
man.addConfigString("server.address", "0.0.0.0:8080")
man.addConfigString("server.cert", "./tools/osquery/kolide.crt")
man.addConfigString("server.key", "./tools/osquery/kolide.key")
// Auth
man.addConfigString("auth.jwt_key", "CHANGEME")
man.addConfigInt("auth.bcrypt_cost", 12)
man.addConfigInt("auth.salt_key_size", 24)
// App
man.addConfigString("app.web_address", "0.0.0.0:8080")
// SMTP
man.addConfigString("smtp.server", "")
man.addConfigString("smtp.username", "")
man.addConfigString("smtp.password", "")
man.addConfigInt("smtp.pool_connections", 4)
man.addConfigInt("smtp.token_key_size", 24)
// Session
man.addConfigInt("session.key_size", 64)
man.addConfigInt("session.expiration_seconds", 60*60*24*90)
man.addConfigString("session.cookie_name", "KolideSession")
// Osquery
man.addConfigString("osquery.enroll_secret", "")
man.addConfigInt("osquery.node_key_size", 24)
man.addConfigString("osquery.status_log_file", "/tmp/osquery_status")
man.addConfigString("osquery.result_log_file", "/tmp/osquery_result")
// Logging
man.addConfigBool("logging.debug", false)
man.addConfigBool("logging.disable_banner", false)
}
// LoadConfig will load the config variables into a fully initialized
// KolideConfig struct
func (man Manager) LoadConfig() KolideConfig {
man.loadConfigFile()
return KolideConfig{
Mysql: MysqlConfig{
Address: man.getConfigString("mysql.address"),
Username: man.getConfigString("mysql.username"),
Password: man.getConfigString("mysql.password"),
Database: man.getConfigString("mysql.database"),
},
Server: ServerConfig{
Address: man.getConfigString("server.address"),
Cert: man.getConfigString("server.cert"),
Key: man.getConfigString("server.key"),
},
Auth: AuthConfig{
JwtKey: man.getConfigString("auth.jwt_key"),
BcryptCost: man.getConfigInt("auth.bcrypt_cost"),
SaltKeySize: man.getConfigInt("auth.salt_key_size"),
},
App: AppConfig{
WebAddress: man.getConfigString("app.web_address"),
},
SMTP: SMTPConfig{
Server: man.getConfigString("smtp.server"),
Username: man.getConfigString("smtp.username"),
Password: man.getConfigString("smtp.password"),
PoolConnections: man.getConfigInt("smtp.pool_connections"),
TokenKeySize: man.getConfigInt("smtp.token_key_size"),
},
Session: SessionConfig{
KeySize: man.getConfigInt("session.key_size"),
ExpirationSeconds: man.getConfigInt("session.expiration_seconds"),
CookieName: man.getConfigString("session.cookie_name"),
},
Osquery: OsqueryConfig{
EnrollSecret: man.getConfigString("osquery.enroll_secret"),
NodeKeySize: man.getConfigInt("osquery.node_key_size"),
StatusLogFile: man.getConfigString("osquery.status_log_file"),
ResultLogFile: man.getConfigString("osquery.result_log_file"),
},
Logging: LoggingConfig{
Debug: man.getConfigBool("logging.debug"),
DisableBanner: man.getConfigBool("logging.disable_banner"),
},
}
}
func initConfig() {
if File != "" {
viper.SetConfigFile(File)
// envNameFromConfigKey converts a config key into the corresponding
// environment variable name
func envNameFromConfigKey(key string) string {
return envPrefix + "_" + strings.ToUpper(strings.Replace(key, ".", "_", -1))
}
// flagNameFromConfigKey converts a config key into the corresponding flag name
func flagNameFromConfigKey(key string) string {
return strings.Replace(key, ".", "_", -1)
}
// Manager manages the addition and retrieval of config values for Kolide
// configs. It's only public API method is LoadConfig, which will return the
// populated KolideConfig struct.
type Manager struct {
viper *viper.Viper
command *cobra.Command
defaults map[string]interface{}
}
// NewManager initializes a Manager wrapping the provided cobra
// command. All config flags will be attached to that command (and inherited by
// the subcommands). Typically this should be called just once, with the root
// command.
func NewManager(command *cobra.Command) Manager {
man := Manager{
viper: viper.New(),
command: command,
defaults: map[string]interface{}{},
}
viper.SetConfigName("kolide")
viper.AddConfigPath(".")
viper.AddConfigPath("$HOME")
viper.AddConfigPath("./tools/app")
viper.AddConfigPath("/etc/kolide")
man.addConfigs()
return man
}
viper.SetConfigType("yaml")
// addDefault will check for duplication, then add a default value to the
// defaults map
func (man Manager) addDefault(key string, defVal interface{}) {
if _, exists := man.defaults[key]; exists {
panic("Trying to add duplicate config for key " + key)
}
viper.SetEnvPrefix("KOLIDE")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
man.defaults[key] = defVal
}
err := viper.ReadInConfig()
// getInterfaceVal is a helper function used by the getConfig* functions to
// retrieve the config value as interface{}, which will then be cast to the
// appropriate type by the getConfig* function.
func (man Manager) getInterfaceVal(key string) interface{} {
interfaceVal := man.viper.Get(key)
if interfaceVal == nil {
var ok bool
interfaceVal, ok = man.defaults[key]
if !ok {
panic("Tried to look up default value for nonexistent config option: " + key)
}
}
return interfaceVal
}
// addConfigString adds a string config to the config options
func (man Manager) addConfigString(key string, defVal string) {
man.command.PersistentFlags().String(flagNameFromConfigKey(key), defVal, "Env: "+envNameFromConfigKey(key))
man.viper.BindPFlag(key, man.command.PersistentFlags().Lookup(flagNameFromConfigKey(key)))
man.viper.BindEnv(key, envNameFromConfigKey(key))
// Add default
man.addDefault(key, defVal)
}
// getConfigString retrieves a string from the loaded config
func (man Manager) getConfigString(key string) string {
interfaceVal := man.getInterfaceVal(key)
stringVal, err := cast.ToStringE(interfaceVal)
if err != nil {
logrus.Infoln("Not reading config file. Relying on environment variables and default values.")
panic("Unable to cast to string for key " + key + ": " + err.Error())
}
return stringVal
}
// addConfigInt adds a int config to the config options
func (man Manager) addConfigInt(key string, defVal int) {
man.command.PersistentFlags().Int(flagNameFromConfigKey(key), defVal, "Env: "+envNameFromConfigKey(key))
man.viper.BindPFlag(key, man.command.PersistentFlags().Lookup(flagNameFromConfigKey(key)))
man.viper.BindEnv(key, envNameFromConfigKey(key))
// Add default
man.addDefault(key, defVal)
}
// getConfigInt retrieves a int from the loaded config
func (man Manager) getConfigInt(key string) int {
interfaceVal := man.getInterfaceVal(key)
intVal, err := cast.ToIntE(interfaceVal)
if err != nil {
panic("Unable to cast to int for key " + key + ": " + err.Error())
}
return intVal
}
// addConfigBool adds a bool config to the config options
func (man Manager) addConfigBool(key string, defVal bool) {
man.command.PersistentFlags().Bool(flagNameFromConfigKey(key), defVal, "Env: "+envNameFromConfigKey(key))
man.viper.BindPFlag(key, man.command.PersistentFlags().Lookup(flagNameFromConfigKey(key)))
man.viper.BindEnv(key, envNameFromConfigKey(key))
// Add default
man.addDefault(key, defVal)
}
// getConfigBool retrieves a bool from the loaded config
func (man Manager) getConfigBool(key string) bool {
interfaceVal := man.getInterfaceVal(key)
boolVal, err := cast.ToBoolE(interfaceVal)
if err != nil {
panic("Unable to cast to bool for key " + key + ": " + err.Error())
}
return boolVal
}
// loadConfigFile handles the loading of the config file.
func (man Manager) loadConfigFile() {
configFile := man.command.PersistentFlags().Lookup("config").Value.String()
if configFile != "" {
man.viper.SetConfigFile(configFile)
} else {
man.viper.SetConfigName("kolide")
man.viper.AddConfigPath(".")
man.viper.AddConfigPath("$HOME")
man.viper.AddConfigPath("./tools/app")
man.viper.AddConfigPath("/etc/kolide")
}
man.viper.SetConfigType("yaml")
err := man.viper.ReadInConfig()
fmt.Println("Using config file: ", man.viper.ConfigFileUsed())
if err != nil {
panic("Error reading config: " + err.Error())
}
setDefaultConfigValue("mysql.address", "localhost:3306")
setDefaultConfigValue("mysql.username", "kolide")
setDefaultConfigValue("mysql.password", "kolide")
setDefaultConfigValue("mysql.database", "kolide")
setDefaultConfigValue("server.address", "0.0.0.0:8080")
setDefaultConfigValue("app.web_address", "0.0.0.0:8080")
setDefaultConfigValue("auth.jwt_key", "CHANGEME")
setDefaultConfigValue("auth.bcrypt_cost", 12)
setDefaultConfigValue("auth.salt_key_size", 24)
setDefaultConfigValue("smtp.token_key_size", 24)
setDefaultConfigValue("smtp.address", "localhost:1025")
setDefaultConfigValue("smtp.pool_connections", 4)
setDefaultConfigValue("session.key_size", 64)
setDefaultConfigValue("session.expiration_seconds", 60*60*24*90)
setDefaultConfigValue("session.cookie_name", "KolideSession")
setDefaultConfigValue("osquery.node_key_size", 24)
setDefaultConfigValue("osquery.status_log_file", "/tmp/osquery_status")
setDefaultConfigValue("osquery.result_log_file", "/tmp/osquery_result")
setDefaultConfigValue("osquery.label_up_interval", 1*time.Minute)
setDefaultConfigValue("logging.debug", false)
setDefaultConfigValue("logging.disable_banner", false)
if viper.GetBool("logging.debug") {
logrus.SetLevel(logrus.DebugLevel)
} else {
logrus.SetLevel(logrus.WarnLevel)
}
if viper.GetBool("logs.json") {
logrus.SetFormatter(&logrus.JSONFormatter{})
}
}

View file

@ -74,6 +74,7 @@ import:
version: fd703108daeb23d77c124d12978e9b6c4f28f034
- package: github.com/spf13/cobra
- package: github.com/spf13/viper
- package: github.com/spf13/cast
- package: gopkg.in/natefinch/lumberjack.v2
version: v2.0
- package: github.com/golang/mock