docs/utils/configuration.go

132 lines
4.0 KiB
Go

// Common configuration elements that may be resused
package utils
import (
"fmt"
"strings"
"github.com/Sirupsen/logrus"
bugsnag_hook "github.com/Sirupsen/logrus/hooks/bugsnag"
"github.com/bugsnag/bugsnag-go"
"github.com/spf13/viper"
)
// Storage is a configuration about what storage backend a server should use
type Storage struct {
Backend string
Source string
}
// ParseServerTLS tries to parse out a valid ServerTLSOpts from a Viper:
// - If TLS is required, both the cert and key must be provided
// - If TLS is not requried, either both the cert and key must be provided or
// neither must be provided
func ParseServerTLS(configuration *viper.Viper, tlsRequired bool) (*ServerTLSOpts, error) {
// unmarshalling into objects does not seem to pick up env vars
tlsOpts := ServerTLSOpts{
ServerCertFile: configuration.GetString("server.tls_cert_file"),
ServerKeyFile: configuration.GetString("server.tls_key_file"),
ClientCAFile: configuration.GetString("server.client_ca_file"),
}
cert, key := tlsOpts.ServerCertFile, tlsOpts.ServerKeyFile
if tlsRequired {
if cert == "" || key == "" {
return nil, fmt.Errorf("both the TLS certificate and key are mandatory")
}
} else {
if (cert == "" && key != "") || (cert != "" && key == "") {
return nil, fmt.Errorf(
"either include both a cert and key file, or neither to disable TLS")
}
}
if cert == "" && key == "" && tlsOpts.ClientCAFile == "" {
return nil, nil
}
return &tlsOpts, nil
}
// ParseLogLevel tries to parse out a log level from a Viper. If there is no
// configuration, defaults to the provided error level
func ParseLogLevel(configuration *viper.Viper, defaultLevel logrus.Level) (
logrus.Level, error) {
logStr := configuration.GetString("logging.level")
if logStr == "" {
return defaultLevel, nil
}
return logrus.ParseLevel(logStr)
}
// ParseStorage tries to parse out Storage from a Viper. If backend and
// URL are not provided, returns a nil pointer.
func ParseStorage(configuration *viper.Viper, allowedBackeneds []string) (*Storage, error) {
store := Storage{
Backend: configuration.GetString("storage.backend"),
Source: configuration.GetString("storage.db_url"),
}
if store.Backend == "" && store.Source == "" {
return nil, nil
}
if store.Source == "" {
return nil, fmt.Errorf("must provide a non-empty database source")
}
store.Backend = strings.ToLower(store.Backend)
for _, backend := range allowedBackeneds {
if backend == store.Backend {
return &store, nil
}
}
return nil, fmt.Errorf(
"must specify one of these supported backends: %s",
strings.Join(allowedBackeneds, ", "))
}
// ParseBugsnag tries to parse out a Bugsnag Configuration from a Viper.
// If no values are provided, returns a nil pointer.
func ParseBugsnag(configuration *viper.Viper) (*bugsnag.Configuration, error) {
// can't unmarshal because we can't add tags to the bugsnag.Configuration
// struct
bugconf := bugsnag.Configuration{
APIKey: configuration.GetString("reporting.bugsnag.api_key"),
ReleaseStage: configuration.GetString("reporting.bugsnag.release_stage"),
Endpoint: configuration.GetString("reporting.bugsnag.endpoint"),
}
if bugconf.APIKey == "" && bugconf.ReleaseStage == "" && bugconf.Endpoint == "" {
return nil, nil
}
if bugconf.APIKey == "" {
return nil, fmt.Errorf("must provide an API key for bugsnag")
}
return &bugconf, nil
}
// utilities for setting up/acting on common configurations
// SetupViper sets up an instance of viper to also look at environment
// variables
func SetupViper(configuration *viper.Viper, envPrefix string) {
configuration.SetEnvPrefix(envPrefix)
configuration.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
configuration.AutomaticEnv()
}
// SetUpBugsnag configures bugsnag and sets up a logrus hook
func SetUpBugsnag(config *bugsnag.Configuration) error {
if config != nil {
bugsnag.Configure(*config)
hook, err := bugsnag_hook.NewBugsnagHook()
if err != nil {
return err
}
logrus.AddHook(hook)
logrus.Debug("Adding logrus hook for Bugsnag")
}
return nil
}