mirror of https://github.com/docker/docs.git
162 lines
4.9 KiB
Go
162 lines
4.9 KiB
Go
// Common configuration elements that may be resused
|
|
|
|
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
bugsnag_hook "github.com/Sirupsen/logrus/hooks/bugsnag"
|
|
"github.com/bugsnag/bugsnag-go"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// Specifies the list of recognized backends
|
|
const (
|
|
MemoryBackend = "memory"
|
|
MySQLBackend = "mysql"
|
|
SqliteBackend = "sqlite3"
|
|
)
|
|
|
|
// Storage is a configuration about what storage backend a server should use
|
|
type Storage struct {
|
|
Backend string
|
|
Source string
|
|
}
|
|
|
|
// GetPathRelativeToConfig gets a configuration key which is a path, and if
|
|
// it is not empty or an absolute path, returns the absolute path relative
|
|
// to the configuration file
|
|
func GetPathRelativeToConfig(configuration *viper.Viper, key string) string {
|
|
configFile := configuration.ConfigFileUsed()
|
|
p := configuration.GetString(key)
|
|
if p == "" || filepath.IsAbs(p) {
|
|
return p
|
|
}
|
|
return filepath.Join(filepath.Dir(configFile), p)
|
|
}
|
|
|
|
// 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
|
|
// The files are relative to the config file used to populate the instance
|
|
// of viper.
|
|
func ParseServerTLS(configuration *viper.Viper, tlsRequired bool) (*ServerTLSOpts, error) {
|
|
// unmarshalling into objects does not seem to pick up env vars
|
|
tlsOpts := ServerTLSOpts{
|
|
ServerCertFile: GetPathRelativeToConfig(configuration, "server.tls_cert_file"),
|
|
ServerKeyFile: GetPathRelativeToConfig(configuration, "server.tls_key_file"),
|
|
ClientCAFile: GetPathRelativeToConfig(configuration, "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. Storage is required (if
|
|
// a backend is not provided, an error will be returned.)
|
|
func ParseStorage(configuration *viper.Viper, allowedBackends []string) (*Storage, error) {
|
|
store := Storage{
|
|
Backend: configuration.GetString("storage.backend"),
|
|
Source: configuration.GetString("storage.db_url"),
|
|
}
|
|
|
|
supported := false
|
|
store.Backend = strings.ToLower(store.Backend)
|
|
for _, backend := range allowedBackends {
|
|
if backend == store.Backend {
|
|
supported = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !supported {
|
|
return nil, fmt.Errorf(
|
|
"must specify one of these supported backends: %s",
|
|
strings.Join(allowedBackends, ", "))
|
|
}
|
|
|
|
if store.Backend == MemoryBackend {
|
|
return &Storage{Backend: MemoryBackend}, nil
|
|
}
|
|
if store.Source == "" {
|
|
return nil, fmt.Errorf(
|
|
"must provide a non-empty database source for %s", store.Backend)
|
|
}
|
|
return &store, nil
|
|
}
|
|
|
|
// 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
|
|
}
|