Skip to content
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

feat: default config #2067

Merged
merged 7 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/flipt/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !linux
// +build !linux

package main

var defaultCfgPath string
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess another alternative is to check the OS at runtime instead of using build tags and an empty var here, anyone have a pref over one or the other?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is cool. It follows the pattern of the other things we are doing with build tags as well, so just for consistency.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt @GeorgeMac ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah im for that. I was going to say, as long as we warn as such. But you've done that, so all gravy to me 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah was debating on if this should be at Info level instead of Warning

6 changes: 6 additions & 0 deletions cmd/flipt/default_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build linux
// +build linux

package main

var defaultCfgPath = "/etc/flipt/config/default.yml"
45 changes: 25 additions & 20 deletions cmd/flipt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ import (
_ "github.com/golang-migrate/migrate/v4/source/file"
)

const (
defaultCfgPath = "/etc/flipt/config/default.yml"
)

var (
cfgPath string
forceMigrate bool
Expand Down Expand Up @@ -65,12 +61,12 @@ var (
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
defaultLogger = zap.Must(defaultConfig(defaultEncoding).Build())
defaultLogger = zap.Must(loggerConfig(defaultEncoding).Build())
userConfigDir, _ = os.UserConfigDir()
fliptConfigFile = filepath.Join(userConfigDir, "flipt", "config.yml")
)

func defaultConfig(encoding zapcore.EncoderConfig) zap.Config {
func loggerConfig(encoding zapcore.EncoderConfig) zap.Config {
return zap.Config{
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
Development: false,
Expand Down Expand Up @@ -169,47 +165,56 @@ func main() {
}
}

// determinePath will figure out which path to use for Flipt configuration.
func determinePath(cfgPath string) string {
// determinePath will figure out which (if any) path to use for Flipt configuration.
func determinePath(cfgPath string) (string, bool) {
if cfgPath != "" {
return cfgPath
return cfgPath, true
}

_, err := os.Stat(fliptConfigFile)
if err == nil {
return fliptConfigFile
return fliptConfigFile, true
}

if !errors.Is(err, fs.ErrNotExist) {
defaultLogger.Warn("unexpected error checking configuration path", zap.String("config_path", fliptConfigFile), zap.Error(err))
}

return defaultCfgPath
return defaultCfgPath, defaultCfgPath != ""
}

func buildConfig() (*zap.Logger, *config.Config) {
path := determinePath(cfgPath)
cfg := config.Default()

// read in config
res, err := config.Load(path)
if err != nil {
defaultLogger.Fatal("loading configuration", zap.Error(err), zap.String("config_path", path))
}
var warnings []string

cfg := res.Config
path, found := determinePath(cfgPath)
if found {
// read in config
res, err := config.Load(path)
if err != nil {
defaultLogger.Fatal("loading configuration", zap.Error(err), zap.String("config_path", path))
}

cfg = res.Config
warnings = res.Warnings
} else {
defaultLogger.Warn("no configuration file found, using defaults")
}

encoding := defaultEncoding
encoding.TimeKey = cfg.Log.Keys.Time
encoding.LevelKey = cfg.Log.Keys.Level
encoding.MessageKey = cfg.Log.Keys.Message

loggerConfig := defaultConfig(encoding)
loggerConfig := loggerConfig(encoding)

// log to file if enabled
if cfg.Log.File != "" {
loggerConfig.OutputPaths = []string{cfg.Log.File}
}

var err error
// parse/set log level
loggerConfig.Level, err = zap.ParseAtomicLevel(cfg.Log.Level)
if err != nil {
Expand All @@ -226,7 +231,7 @@ func buildConfig() (*zap.Logger, *config.Config) {
logger := zap.Must(loggerConfig.Build())

// print out any warnings from config parsing
for _, warning := range res.Warnings {
for _, warning := range warnings {
logger.Warn("configuration warning", zap.String("message", warning))
}

Expand Down
2 changes: 1 addition & 1 deletion config/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func defaultConfig(t *testing.T) (conf map[string]any) {
Result: &conf,
})
require.NoError(t, err)
require.NoError(t, dec.Decode(config.DefaultConfig()))
require.NoError(t, dec.Decode(config.Default()))

// adapt converts instances of time.Duration to their
// string representation, which CUE is going to validate
Expand Down
4 changes: 2 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,8 @@ func stringToSliceHookFunc() mapstructure.DecodeHookFunc {
}
}

// DefaultConfig is the base config used when no configuration is explicit provided.
func DefaultConfig() *Config {
// Default is the base config used when no configuration is explicit provided.
func Default() *Config {
dbRoot, err := defaultDatabaseRoot()
if err != nil {
panic(err)
Expand Down
42 changes: 21 additions & 21 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,13 @@ func TestLoad(t *testing.T) {
{
name: "defaults",
path: "./testdata/default.yml",
expected: DefaultConfig,
expected: Default,
},
{
name: "deprecated tracing jaeger enabled",
path: "./testdata/deprecated/tracing_jaeger_enabled.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Tracing.Enabled = true
cfg.Tracing.Exporter = TracingJaeger
return cfg
Expand All @@ -229,7 +229,7 @@ func TestLoad(t *testing.T) {
name: "deprecated cache memory enabled",
path: "./testdata/deprecated/cache_memory_enabled.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Cache.Enabled = true
cfg.Cache.Backend = CacheMemory
cfg.Cache.TTL = -time.Second
Expand All @@ -243,7 +243,7 @@ func TestLoad(t *testing.T) {
{
name: "deprecated cache memory items defaults",
path: "./testdata/deprecated/cache_memory_items.yml",
expected: DefaultConfig,
expected: Default,
warnings: []string{
"\"cache.memory.enabled\" is deprecated. Please use 'cache.enabled' and 'cache.backend' instead.",
},
Expand All @@ -252,7 +252,7 @@ func TestLoad(t *testing.T) {
name: "deprecated ui disabled",
path: "./testdata/deprecated/ui_disabled.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.UI.Enabled = false
return cfg
},
Expand All @@ -261,14 +261,14 @@ func TestLoad(t *testing.T) {
{
name: "deprecated experimental filesystem_storage",
path: "./testdata/deprecated/experimental_filesystem_storage.yml",
expected: DefaultConfig,
expected: Default,
warnings: []string{"\"experimental.filesystem_storage\" is deprecated. The experimental filesystem storage backend has graduated to a stable feature. Please use 'storage' instead."},
},
{
name: "cache no backend set",
path: "./testdata/cache/default.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Cache.Enabled = true
cfg.Cache.Backend = CacheMemory
cfg.Cache.TTL = 30 * time.Minute
Expand All @@ -279,7 +279,7 @@ func TestLoad(t *testing.T) {
name: "cache memory",
path: "./testdata/cache/memory.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Cache.Enabled = true
cfg.Cache.Backend = CacheMemory
cfg.Cache.TTL = 5 * time.Minute
Expand All @@ -291,7 +291,7 @@ func TestLoad(t *testing.T) {
name: "cache redis",
path: "./testdata/cache/redis.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Cache.Enabled = true
cfg.Cache.Backend = CacheRedis
cfg.Cache.TTL = time.Minute
Expand All @@ -311,7 +311,7 @@ func TestLoad(t *testing.T) {
name: "tracing zipkin",
path: "./testdata/tracing/zipkin.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Tracing.Enabled = true
cfg.Tracing.Exporter = TracingZipkin
cfg.Tracing.Zipkin.Endpoint = "http://localhost:9999/api/v2/spans"
Expand All @@ -322,7 +322,7 @@ func TestLoad(t *testing.T) {
name: "database key/value",
path: "./testdata/database.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Database = DatabaseConfig{
Protocol: DatabaseMySQL,
Host: "localhost",
Expand Down Expand Up @@ -385,7 +385,7 @@ func TestLoad(t *testing.T) {
name: "authentication token with provided bootstrap token",
path: "./testdata/authentication/token_bootstrap_token.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Authentication.Methods.Token.Method.Bootstrap = AuthenticationMethodTokenBootstrapConfig{
Token: "s3cr3t!",
Expiration: 24 * time.Hour,
Expand All @@ -397,7 +397,7 @@ func TestLoad(t *testing.T) {
name: "authentication session strip domain scheme/port",
path: "./testdata/authentication/session_domain_scheme_port.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Authentication.Required = true
cfg.Authentication.Session.Domain = "localhost"
cfg.Authentication.Methods = AuthenticationMethods{
Expand All @@ -423,7 +423,7 @@ func TestLoad(t *testing.T) {
name: "authentication kubernetes defaults when enabled",
path: "./testdata/authentication/kubernetes.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Authentication.Methods = AuthenticationMethods{
Kubernetes: AuthenticationMethod[AuthenticationMethodKubernetesConfig]{
Enabled: true,
Expand All @@ -445,7 +445,7 @@ func TestLoad(t *testing.T) {
name: "advanced",
path: "./testdata/advanced.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()

cfg.Audit = AuditConfig{
Sinks: SinksConfig{
Expand Down Expand Up @@ -598,7 +598,7 @@ func TestLoad(t *testing.T) {
name: "version v1",
path: "./testdata/version/v1.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Version = "1.0"
return cfg
},
Expand All @@ -622,7 +622,7 @@ func TestLoad(t *testing.T) {
name: "local config provided",
path: "./testdata/storage/local_provided.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Storage = StorageConfig{
Type: LocalStorageType,
Local: &Local{
Expand All @@ -636,7 +636,7 @@ func TestLoad(t *testing.T) {
name: "git config provided",
path: "./testdata/storage/git_provided.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Storage = StorageConfig{
Type: GitStorageType,
Git: &Git{
Expand All @@ -662,7 +662,7 @@ func TestLoad(t *testing.T) {
name: "s3 config provided",
path: "./testdata/storage/s3_provided.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Storage = StorageConfig{
Type: ObjectStorageType,
Object: &Object{
Expand All @@ -680,7 +680,7 @@ func TestLoad(t *testing.T) {
name: "s3 full config provided",
path: "./testdata/storage/s3_full.yml",
expected: func() *Config {
cfg := DefaultConfig()
cfg := Default()
cfg.Storage = StorageConfig{
Type: ObjectStorageType,
Object: &Object{
Expand Down Expand Up @@ -790,7 +790,7 @@ func TestLoad(t *testing.T) {

func TestServeHTTP(t *testing.T) {
var (
cfg = DefaultConfig()
cfg = Default()
req = httptest.NewRequest("GET", "http://example.com/foo", nil)
w = httptest.NewRecorder()
)
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/preferences/preferencesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import { createSlice } from '@reduxjs/toolkit';
import { fetchConfigAsync } from '~/app/meta/metaSlice';
import { RootState } from '~/store';
import { Theme, Timezone } from '~/types/Preferences';
import { fetchConfigAsync } from '~/app/meta/metaSlice';

export const preferencesKey = 'preferences';

Expand Down
Loading