config

package
v3.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2020 License: MIT Imports: 19 Imported by: 26

README

Config module

This module provides features to read and merge Flamingo configurations. Also it provides template functions to access configurations in your template.

Configurations are defined and used by the individual modules. The modules should come with a documentation which configurations/feature-flags they support.

Basics

Configurations are yml files located in config folder.

The configuration syntax is to specify sections either with . or as yaml maps:

foo:
  bar: x

is the same as

foo.bar: x

Configuration values can also be read from environment variables during the loading process with the syntax:

auth.secret: '%%ENV:KEYCLOAK_SECRET%%'

or

auth.secret: '%%ENV:KEYCLOAK_SECRET%%default_value%%'

In the second case, Flamingo falls back to default_value if the environment variable is not set or empty.

Configuration can be used:

  • either by the config() templatefunction in your template
  • or via dependency injection from Dingo

Loaded Configuration files

The following configuration files will be loaded from config folder:

  • config.yml
  • routes.yml
  • optional: config_($CONTEXT).yml
  • optional: routes_($CONTEXT).yml
  • config_local.yml
  • routes_local.yml

You can set different contexts with the environment variable CONTEXT and this will cause Flamingo to load additional configuration files.

e.g. starting Flamingo with

CONTEXT="dev" go run project.go serve

Will cause Flamingo to additionally load the config file config/config_dev.yml

You can also load multiple extra configuration files - e.g. starting Flamingo with

CONTEXT="dev:testdata" go run project.go serve

Will cause Flamingo to additionally load the config files "config/config_dev.yml" and "config/config_testdata.yml" in the given order.

Additional configuration files from outside

Flamingo can load multiple additional yaml/cue files, which must be given in the environment variable CONTEXTFILE, separated by :.

The files can be given by using relative paths from the working directory or absolute paths.

CONTEXTFILE="../../myCfg.yml:/var/flamingo/cfg/main.yml:/var/flamingo/cfg/additional.cue" go run project.go serve
Additional temporary configuration

You can set any configuration value within the run command by using the --flamingo-config flag:

go run project.go serve --flamingo-config "auth.secret: mySecret" --flamingo-config "other.secret: mySecret"

The flag's values are expected to be valid yaml. The flag can be used multiple times.

Configurations provided via --flamingo-config flag overwrite all values provided in yaml files.

Priority of configuration

If multiple sources define the same configuration key, the value from the last loaded source is taken. The order of loading is:

  1. All files from config directory
  2. config.yml
  3. routes.yml
  4. All context files given in the environment variable CONTEXT 1. config_($CONTEXT).yml 1. routes_($CONTEXT).yml
  5. config_local.yml
  6. routes_local.yml
  7. All files given in the environment variable CONTEXTFILE
  8. All values given via --flamingo-config flag
Debugging configuration loading

By stating --flamingo-config-log, you can enable the configuration loader's debug log, which prints all handled files to the output using go's log package, because the flamingo.Logger is not available yet in this early state of bootstrapping.

Injecting configurations

Asking for either a concrete value via e.g. foo.bar is possible, as well as getting a whole config.Map instance by a partially-selector, e.g. foo. This would be a Map with element bar.

All configuration values are registered as Dingo annotated binding and can be requested using the inject tag. To get this in the arguments of the Inject function or a dingo provider, you will have to wrap it by an anonymous struct.

For example:

// Inject dependencies
func (m *Module) Inject(
	cfg *struct {
	CompleteConfig config.Map `inject:"config:mymodule"`
	Title          string     `inject:"config:mymodule.title"`
	Amount         int        `inject:"config:mymodule.amount"`
	Flag           bool       `inject:"config:mymodule.flag"`
},
) *Module {
	if cfg != nil {
		m.title = cfg.Title
		m.amount = cfg.Amount
		m.flag = cfg.Flag
		m.cfg = cfg.CompleteConfig
	}

	return m
}

Deeply nested config maps can be marshaled into structs for convenience.

The result struct must match exactly the structure and types of the config map and all fields must be exported.

err := m.MarshalTo(&result)

Using multiple configuration areas:

A Flamingo application can have multiple config.Area - that is essentially useful for localisation. See [Flamingo Bootstrap](../1. Flamingo Basics/7. Flamingo Bootstrap.md)

Convert Yaml to Cue

sed "s/\'%%ENV:\(.*\)%%\(.*\)%%\'/*flamingo.os.env.\1 | \"\2\"/g"
sed "s/\"%%ENV:\(.*\)%%\(.*\)%%\"/*flamingo.os.env.\1 | \"\2\"/g"
sed "s/\'%%ENV:\(.*\)%%\'/flamingo.os.env.\1/g"
sed "s/\"%%ENV:\(.*\)%%\"/flamingo.os.env.\1/g"

Documentation

Overview

Package config provides supporting code for multi-tenant setups

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cmd

func Cmd(area *Area) *cobra.Command

Cmd command: The Area for which the config is to be printed need to be passed. This will be done by Dingo if a Provider is used for example.

func Load

func Load(root *Area, basedir string, options ...LoadOption) error

Load configuration in basedir

func LoadConfigFile

func LoadConfigFile(area *Area, file string) error

LoadConfigFile loads a config Deprecated: do not arbitrarily load anything anymore, use Area.Load

func TryModules added in v3.1.0

func TryModules(cm Map, modules ...dingo.Module) error

TryModules evaluates flamingo modules to test cue config and dingo bindings

Types

type Area

type Area struct {
	Name string

	Parent   *Area
	Childs   []*Area
	Modules  []dingo.Module
	Injector *dingo.Injector

	Routes        []Route
	Configuration Map
	LoadedConfig  Map // Deprecated: empty and should not be used anymore
	// contains filtered or unexported fields
}

Area defines a configuration area for multi-site setups it is initialized by project main package and partly loaded by config files

func MergeFrom

func MergeFrom(baseContext, incomingContext Area) *Area

MergeFrom merges two Contexts into a new one We do not merge config, as we use the DI to handle it

func NewArea

func NewArea(name string, modules []dingo.Module, childs ...*Area) *Area

NewArea creates a new Area with optional childs

func (*Area) Config

func (area *Area) Config(key string) (interface{}, bool)

Config get a config value (recursive thru all parents if possible)

func (*Area) Flat

func (area *Area) Flat() (map[string]*Area, error)

Flat returns a map of name->*Area of contexts, were all values have been inherited (yet overridden) of the parent context tree.

func (*Area) GetFlatContexts

func (area *Area) GetFlatContexts() ([]*Area, error)

GetFlatContexts returns a map of context-relative-name->*Area, which has been flatted to inherit all parent's tree settings such as DI & co, and filtered to only list tree nodes specified by Contexts of area. Deprecated: just do it yourself if necessary, with Flat()

func (*Area) GetInitializedInjector

func (area *Area) GetInitializedInjector() (*dingo.Injector, error)

GetInitializedInjector returns initialized container based on the configuration we derive our injector from our parent

func (*Area) HasConfigKey

func (area *Area) HasConfigKey(key string) bool

HasConfigKey checks recursive if the config has a given key

type CueConfigModule added in v3.1.0

type CueConfigModule interface {
	CueConfig() string
}

CueConfigModule provides a cue schema with default configuration which is used to validate and set config

type DefaultConfigModule

type DefaultConfigModule interface {
	DefaultConfig() Map
}

DefaultConfigModule is used to get a module's default configuration Deprecated: use CueConfigModule instead

type LoadConfig added in v3.1.0

type LoadConfig struct {
	// contains filtered or unexported fields
}

LoadConfig provides configuration for the loader

type LoadOption added in v3.1.0

type LoadOption func(*LoadConfig)

LoadOption to be passed to Load(, ...)

func AdditionalConfig added in v3.1.0

func AdditionalConfig(addtionalConfig []string) LoadOption

AdditionalConfig adds additional config values (yaml strings) to the config

func CueDebug added in v3.1.0

func CueDebug(path []string, callback func([]byte, error)) LoadOption

CueDebug enables a cue.Instance debugger. This is part of a dev-api and might change!

func DebugLog added in v3.1.0

func DebugLog(debug bool) LoadOption

DebugLog enables/disabled detailed debug logging

func LegacyMapping added in v3.1.0

func LegacyMapping(mapLegacy, logLegacy bool) LoadOption

LegacyMapping controls if flamingo legacy config mapping happens

type Map

type Map map[string]interface{}

Map contains configuration

func (Map) Add

func (m Map) Add(cfg Map) error

Add to the map (deep merge)

func (Map) Flat

func (m Map) Flat() Map

Flat map

func (Map) Get

func (m Map) Get(key string) (interface{}, bool)

Get a value by it's path

func (Map) MapInto

func (m Map) MapInto(out interface{}) error

MapInto tries to map the configuration map into a given interface

type Module

type Module struct {
	Map
}

Module defines a dingo module which automatically binds provided config. Normally this module is not included in your flamingo projects bootstrap.

Its can be useful for testing dingo.Module that require certain configuration to be set before. E.g.:

cfgModule := &config.Module{
		Map: config.Map{
			"redirects.useInRouter":       true,
			"redirects.useInPrefixRouter": true,
		},
	}

	if err := dingo.TryModule(cfgModule, module); err != nil {
		t.Error(err)
	}

func (*Module) Configure

func (m *Module) Configure(injector *dingo.Injector)

Configure the Module

type OverrideConfigModule

type OverrideConfigModule interface {
	OverrideConfig(current Map) Map
}

OverrideConfigModule allows to override config dynamically

type Route

type Route struct {
	Path       string
	Controller string
	Name       string
}

Route defines the yaml structure for a route, consisting of a path and a controller, as well as optional args

type Slice

type Slice []interface{}

Slice contains a list of configuration options

func (Slice) MapInto

func (s Slice) MapInto(out interface{}) error

MapInto tries to map the configuration map into a given interface

type TemplateFunc

type TemplateFunc struct {
	// contains filtered or unexported fields
}

TemplateFunc allows to retrieve config variables

func (*TemplateFunc) Func

func (c *TemplateFunc) Func(ctx context.Context) interface{}

Func returns the template function

func (*TemplateFunc) Inject

func (c *TemplateFunc) Inject(area *Area)

Inject dependencies

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL