Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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: 2 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,25 +133,23 @@ Key Default Description
============================ ============== =================================================================================================================================================================================
****
address localhost:1323 Address and port the server will be listening to
configfile Nuts config file
configfile nuts.yaml Nuts config file
datadir ./data Directory where the node stores its files.
strictmode false When set, insecure settings are forbidden.
verbosity info Log level (trace, debug, info, warn, error)
**Crypto**
crypto.fspath ./ When file system is used as storage, this configures the path where key material and the truststore are persisted, default: ./
crypto.storage fs Storage to use, 'fs' for file system, default: fs
**Network**
network.advertHashesInterval 2000 Interval (in milliseconds) that specifies how often the node should broadcast its last hashes to other nodes.
network.bootstrapNodes Space-separated list of bootstrap nodes (`<host>:<port>`) which the node initially connect to.
network.certFile PEM file containing the server certificate for the gRPC server. Required when `enableTLS` is `true`.
network.certKeyFile PEM file containing the private key of the server certificate. Required when `network.enableTLS` is `true`.
network.databaseFile network.db File path to the network database.
network.enableTLS true Whether to enable TLS for inbound gRPC connections. If set to `true` (which is default) `certFile` and `certKeyFile` MUST be configured.
network.grpcAddr \:5555 Local address for gRPC to listen on. If empty the gRPC server won't be started and other nodes will not be able to connect to this node (outbound connections can still be made).
network.publicAddr Public address (of this node) other nodes can use to connect to it. If set, it is registered on the nodelist.
network.trustStoreFile PEM file containing the trusted CA certificates for authenticating remote gRPC servers.
**Verifiable Data Registry**
vdr.clientTimeout 10 Time-out for the client in seconds (e.g. when using the CLI), default: 10
vdr.datadir ./data Location of data files, default: ./data
============================ ============== =================================================================================================================================================================================

This table is automatically generated using the configuration flags in the core and engines. When they're changed
Expand Down
Binary file removed cmd/network.db
Binary file not shown.
20 changes: 5 additions & 15 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/nuts-foundation/nuts-node/test/io"
"github.com/stretchr/testify/assert"
"os"
"path"
"testing"
)

Expand Down Expand Up @@ -50,22 +49,13 @@ func Test_rootCmd(t *testing.T) {
return echoServer
}

expectedAddress := "some-other-address:1323"

testDirectory := io.TestDirectory(t)
os.Setenv("NUTS_ADDRESS", expectedAddress)
defer os.Unsetenv("NUTS_ADDRESS")
os.Setenv("NUTS_NETWORK_DATABASEFILE", path.Join(testDirectory, "network.db"))
defer os.Unsetenv("NUTS_NETWORK_DATABASEFILE")
os.Setenv("NUTS_VDR_DATADIR", path.Join(testDirectory, "vdr"))
defer os.Unsetenv("NUTS_VDR_DATADIR")
os.Setenv("NUTS_CRYPTO_FSPATH", path.Join(testDirectory, "crypto"))
defer os.Unsetenv("NUTS_CRYPTO_FSPATH")

os.Setenv("NUTS_DATADIR", testDirectory)
defer os.Unsetenv("NUTS_DATADIR")
os.Args = []string{"nuts", "server"}

type Cfg struct {
Address string
Datadir string
}
var engineCfg = &Cfg{}
engine := &core.Engine{
Expand All @@ -78,9 +68,9 @@ func Test_rootCmd(t *testing.T) {

Execute(system)
// Assert global config contains overridden property
assert.Equal(t, expectedAddress, system.Config.Address)
assert.Equal(t, testDirectory, system.Config.Datadir)
// Assert engine config is injected
assert.Equal(t, expectedAddress, engineCfg.Address)
assert.Equal(t, testDirectory, engineCfg.Datadir)
})
}

Expand Down
25 changes: 15 additions & 10 deletions core/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,35 @@ const defaultConfigFile = "nuts.yaml"
const configFileFlag = "configfile"
const loggerLevelFlag = "verbosity"
const addressFlag = "address"
const datadirFlag = "datadir"
const defaultLogLevel = "info"
const defaultAddress = "localhost:1323"
const strictModeFlag = "strictmode"
const defaultStrictMode = false
const defaultDatadir = "./data"

// NutsGlobalConfig has global settings.
type NutsGlobalConfig struct {
// NutsConfig has global settings.
type NutsConfig struct {
Address string `koanf:"address"`
Verbosity string `koanf:"verbosity"`
Strictmode bool `koanf:"strictmode"`
Datadir string `koanf:"datadir"`
configMap *koanf.Koanf
}

// NewNutsConfig creates a new config with some defaults
func NewNutsConfig() *NutsGlobalConfig {
return &NutsGlobalConfig{
func NewNutsConfig() *NutsConfig {
return &NutsConfig{
configMap: koanf.New(defaultDelimiter),
Address: defaultAddress,
Verbosity: defaultLogLevel,
Strictmode: defaultStrictMode,
Datadir: defaultDatadir,
}
}

// Load follows the load order of configfile, env vars and then commandline param
func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) {
func (ngc *NutsConfig) Load(cmd *cobra.Command) (err error) {
cmd.PersistentFlags().AddFlagSet(ngc.flagSet())

ngc.configMap = koanf.New(defaultDelimiter)
Expand Down Expand Up @@ -111,7 +115,7 @@ func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) {
}

// getConfigfile returns the configfile path in the following order: commandline param, env variable, default path
func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string {
func (ngc *NutsConfig) getConfigfile(cmd *cobra.Command) string {
k := koanf.New(defaultDelimiter)

// load env flags
Expand All @@ -133,22 +137,23 @@ func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string {
return k.String(configFileFlag)
}

func (ngc *NutsGlobalConfig) flagSet() *pflag.FlagSet {
func (ngc *NutsConfig) flagSet() *pflag.FlagSet {
flagSet := pflag.NewFlagSet("config", pflag.ContinueOnError)
flagSet.String(configFileFlag, defaultConfigFile, "Nuts config file")
flagSet.String(loggerLevelFlag, defaultLogLevel, "Log level (trace, debug, info, warn, error)")
flagSet.String(addressFlag, defaultAddress, "Address and port the server will be listening to")
flagSet.Bool(strictModeFlag, defaultStrictMode, "When set, insecure settings are forbidden.")
flagSet.String(datadirFlag, defaultDatadir, "Directory where the node stores its files.")
return flagSet
}

// PrintConfig return the current config in string form
func (ngc *NutsGlobalConfig) PrintConfig() string {
func (ngc *NutsConfig) PrintConfig() string {
return ngc.configMap.Sprint()
}

// InjectIntoEngine takes the loaded config and sets the engine's config struct
func (ngc *NutsGlobalConfig) InjectIntoEngine(e *Engine) error {
func (ngc *NutsConfig) InjectIntoEngine(e *Engine) error {
// ignore if no target for injection
if e.Config != nil {
return ngc.configMap.Unmarshal(e.ConfigKey, e.Config)
Expand All @@ -159,7 +164,7 @@ func (ngc *NutsGlobalConfig) InjectIntoEngine(e *Engine) error {

// RegisterFlags adds the flagSet of an engine to the commandline, flag names are prefixed if needed
// The passed command must be the root command not the engine.Cmd (unless they are the same)
func (ngc *NutsGlobalConfig) RegisterFlags(cmd *cobra.Command, e *Engine) {
func (ngc *NutsConfig) RegisterFlags(cmd *cobra.Command, e *Engine) {
if e.FlagSet != nil {
cmd.PersistentFlags().AddFlagSet(e.FlagSet)
}
Expand Down
11 changes: 8 additions & 3 deletions core/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
package core

import (
"fmt"
"net/url"
"os"

"github.com/labstack/echo/v4"
"github.com/spf13/cobra"
Expand All @@ -40,7 +42,7 @@ type System struct {
// engines is the slice of all registered engines
engines []*Engine
// Config holds the global and raw config
Config *NutsGlobalConfig
Config *NutsConfig
}

// Load loads the config and injects config values into engines
Expand Down Expand Up @@ -94,10 +96,13 @@ func (system *System) Shutdown() error {
// Configure configures all engines in the system.
func (system *System) Configure() error {
var err error
if err = os.MkdirAll(system.Config.Datadir, os.ModePerm); err != nil {
return fmt.Errorf("unable to create datadir (dir=%s): %w", system.Config.Datadir, err)
}
return system.VisitEnginesE(func(engine *Engine) error {
// only if Engine is dynamically configurable
if engine.Configurable != nil {
err = engine.Configure()
err = engine.Configure(*system.Config)
}
return err
})
Expand Down Expand Up @@ -160,7 +165,7 @@ type Runnable interface {
// When an engine implements the Configurable interface, it will be called before startup.
// Configure should only be called once per engine instance
type Configurable interface {
Configure() error
Configure(config NutsConfig) error
}

// Diagnosable allows the implementer, mostly engines, to return diagnostics.
Expand Down
23 changes: 15 additions & 8 deletions core/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,23 @@ func TestSystem_Shutdown(t *testing.T) {
}

func TestSystem_Configure(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
t.Run("ok", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

r := NewMockConfigurable(ctrl)
r.EXPECT().Configure()
r := NewMockConfigurable(ctrl)
r.EXPECT().Configure(gomock.Any())

system := NewSystem()
system.RegisterEngine(&Engine{})
system.RegisterEngine(&Engine{Configurable: r})
assert.Nil(t, system.Configure())
system := NewSystem()
system.RegisterEngine(&Engine{})
system.RegisterEngine(&Engine{Configurable: r})
assert.Nil(t, system.Configure())
})
t.Run("unable to create datadir", func(t *testing.T) {
system := NewSystem()
system.Config = &NutsConfig{Datadir: "engine_test.go"}
assert.Error(t, system.Configure())
})
}

func TestSystem_Diagnostics(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion core/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type metricsEngine struct{}

// Configure configures the MetricsEngine.
// It configures and registers the prometheus collector
func (metricsEngine) Configure() error {
func (metricsEngine) Configure(_ NutsConfig) error {
collectors := []prometheus.Collector{
prometheus.NewGoCollector(),
prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}),
Expand Down
4 changes: 2 additions & 2 deletions core/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (

func TestNewMetricsEngine(t *testing.T) {
mEngine := NewMetricsEngine()
_ = mEngine.Configure()
_ = mEngine.Configure(NutsConfig{})
e := echo.New()
mEngine.Routes(e)

Expand All @@ -56,7 +56,7 @@ func TestNewMetricsEngine(t *testing.T) {
})

t.Run("calling configure twice is ok", func(t *testing.T) {
err := mEngine.Configure()
err := mEngine.Configure(NutsConfig{})

assert.NoError(t, err)
})
Expand Down
8 changes: 4 additions & 4 deletions core/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 6 additions & 14 deletions crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,20 @@ import (
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/crypto/storage"
"io"
"path"
"sync"
"time"
)

// Config holds the values for the crypto engine
type Config struct {
Storage string
Fspath string
}

func (cc Config) getFSPath() string {
if cc.Fspath == "" {
return DefaultCryptoConfig().Fspath
}

return cc.Fspath
}

// DefaultCryptoConfig returns a Config with sane defaults
func DefaultCryptoConfig() Config {
return Config{
Storage: "fs",
Fspath: "./",
}
}

Expand Down Expand Up @@ -106,22 +97,23 @@ func Instance() *Crypto {
}

// Configure loads the given configurations in the engine. Any wrong combination will return an error
func (client *Crypto) Configure() error {
func (client *Crypto) Configure(config core.NutsConfig) error {
var err error
client.configOnce.Do(func() {
if err = client.doConfigure(); err == nil {
if err = client.doConfigure(config); err == nil {
client.configDone = true
}
})
return err
}

func (client *Crypto) doConfigure() error {
func (client *Crypto) doConfigure(config core.NutsConfig) error {
if client.Config.Storage != "fs" && client.Config.Storage != "" {
return errors.New("only fs backend available for now")
}
var err error
if client.Storage, err = storage.NewFileSystemBackend(client.Config.getFSPath()); err != nil {
fsPath := path.Join(config.Datadir, "crypto")
if client.Storage, err = storage.NewFileSystemBackend(fsPath); err != nil {
return err
}
return nil
Expand Down
Loading