serbrech / staert

Merge your configuration sources

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Stært

Travis branch Coverage Status license

Stært is a Go library for loading and merging a program configuration structure from many sources.

Overview

Stært was born in order to merge two sources of Configuration (Flæg, Toml). Now it also supports Key-Value Store. We developed Flæg and Stært in order to simplify configuration maintenance on Træfik.

Features

  • Load your Configuration structure from many sources
  • Keep your Configuration structure values unchanged if no overwriting (support defaults values)
  • Three native sources :
  • An Interface to add your own sources
  • Handle pointers field :
    • You can give a structure of default values for pointers
    • Same comportment as Flæg
  • Stært is Command oriented
    • It use flaeg.Command
    • Same comportment as Flæg commands
    • Stært supports only one Command (the Root-Command)
    • Flæg allows you to use many Commands
    • Only Flæg will be used if a Sub-Command is called. (because Config type could be different from one Command to another)
    • You can add Metadata "parseAllSources" -> "true" to a Sub-Command if you want to parse all sources (it requires the same Config type on the Sub-Command and the Root-Command)

Getting Started

The configuration

It works on your own Configuration structure, like this one :

package example

import (
	"fmt"
	"github.com/containous/flaeg"
	"github.com/containous/staert"
	"os"
)

//Configuration is a struct which contains all differents type to field
type Configuration struct {
	IntField     int                      `description:"An integer field"`
	StringField  string                   `description:"A string field"`
	PointerField *PointerSubConfiguration `description:"A pointer field"`
}

//PointerSubConfiguration is a SubStructure Configuration
type PointerSubConfiguration struct {
	BoolField  bool    `description:"A boolean field"`
	FloatField float64 `description:"A float field"`
}

Let's initialize it:

 func main() {
	//Init with default value
	config := &Configuration{
		IntField:    1,
		StringField: "init",
		PointerField: &PointerSubConfiguration{
			FloatField: 1.1,
		},
	}
	//Set default pointers value
	defaultPointersConfig := &Configuration{
		PointerField: &PointerSubConfiguration{
			BoolField:  true,
			FloatField: 99.99,
		},
	}

The command

Stært uses flaeg.Command Structure, like this :

    //Create Command
    command:=&flaeg.Command{
        Name:"example",
        Description:"This is an example of description",
        Config:config,
        DefaultPointersConfig:defaultPointersConfig,
        Run: func() error {
            fmt.Printf("Run example with the config :\n%+v\n",config)
 			fmt.Printf("PointerField contains:%+v\n", config.PointerField)
            return nil
        }
    }

Use stært with sources

Init Stært

    s:=staert.NewStaert(command)

Init TOML source

     toml:=staert.NewTomlSource("example", []string{"./toml/", "/any/other/path"})

Init Flæg source

     f:=flaeg.New(command, os.Args[1:])

Add sources

Add TOML and flæg sources

    s.AddSource(toml)
    s.AddSource(f)

NB : You can change order, so that, flaeg configuration will overwrite toml one

Load your configuration

Just call LoadConfig function :

	loadedConfig, err := s.LoadConfig();
    if err != nil {
		//OOPS
	}
	//DO WHAT YOU WANT WITH loadedConfig 
	//OR CALL RUN FUNC

You can call Run

Run function will call the func run() from the command :

    if err := s.Run(); err != nil {
		//OOPS
	}
 }

NB : If you didn't call LoadConfig() before, your func run() will use your original configuration

Let's run example

TOML file ./toml/example.toml :

IntField= 2
[PointerField]

We can run the example program using folowing CLI arguments :

$ ./example --stringfield=owerwrittenFromFlag --pointerfield.floatfield=55.55
Run example with the config :
&{IntField:2 StringField:owerwrittenFromFlag PointerField:0xc82000ec80}
PointerField contains:&{BoolField:true FloatField:55.55}

Full example :

Tagoæl is a trivial example which shows how Stært can be use. This funny golang progam takes its configuration from both TOML and Flaeg sources to display messages.

$ ./tagoael -h
tagoæl is an enhanced Hello World program to display messages with
an advanced configuration mechanism provided by flæg & stært.

flæg:   https://github.com/containous/flaeg
stært:  https://github.com/containous/staert
tagoæl: https://github.com/debovema/tagoael


Usage: tagoael [--flag=flag_argument] [-f[flag_argument]] ...     set flag_argument to flag(s)
   or: tagoael [--flag[=true|false| ]] [-f[true|false| ]] ...     set true/false to boolean flag(s)

Flags:
        -c, --commandlineoverridesconfigfile               Whether configuration from command line overrides configuration from configuration file or not. (default "true")
        --configfile                                       Configuration file to use (TOML). (default "tagoael")
        -i, --displayindex                                 Whether to display index of each message (default "false")
        -m, --messagetodisplay                             Message to display (default "HELLO WOLRD")
        -n, --numbertodisplay                              Number of messages to display (default "1000")
        -h, --help                                         Print Help (this message) and exit

Thank you @debovema for this work :)

KvStore

As with Flæg and Toml sources, the configuration structure can be loaded from a Key-Value Store. The package libkv provides connection to many KV Store like Consul, Etcd or Zookeeper.

The whole configuration structure is stored, using architecture like this pattern :

  • Key : <prefix1>/<prefix2>/.../<fieldNameLevel1>/<fieldNameLevel2>/.../<fieldName>
  • Value : <value>

It handles :

  • All mapstructure features(bool, int, ... , Squashed Embedded Sub struct, Pointer).
  • Maps with pattern : .../<MapFieldName>/<mapKey> -> <mapValue> (Struct as key not supported)
  • Slices (and Arrays) with pattern : .../<SliceFieldName>/<SliceIndex> -> <value>

Note : Hopefully, we provide the function StoreConfig to store your configuration structure ;)

KvSource

KvSource implements Source:

type KvSource struct {
	store.Store
	Prefix string // like this "prefix" (witout the /)
}

Initialize

It can be initialized like this :

	kv, err := staert.NewKvSource(backend store.Backend, addrs []string, options *store.Config, prefix string)

LoadConfig

You can directly load data from the KV Store into the config structure (given by reference)

	config := &ConfigStruct{} // Here your configuration structure by reference
	err := kv.Parse(config)
	//DO WHAT YOU WANT WITH config

Add to Stært sources

Or you can add this source to Stært, as with other sources

	s.AddSource(kv)

StoreConfig

You can also store your whole configuration structure into the KV Store :

	// We assume that config is Initialazed
	err := kv.StoreConfig(config)

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

About

Merge your configuration sources

License:MIT License


Languages

Language:Go 100.0%