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: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# v1.1.0

- add ability to find from certain file sources
- fix common test case config files
- update README.md

# v1.0.1

- add vault auth username/password & roleid/secretid params for cli usage
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ SYSLOG_NG_DOMAIN=custom-syslog-ng-domain go run ./cfg.go
### Api

- `New(context.Context, config.Options) (*config.Config, error)`. Creates new config instance. Provide `config.Options` object to set config path and etc. If configuration directory is empty the `ErrEmptyDir` sentinel error will be returned.
- `(*config.Config) Get(context.Context, path string) (any, bool)`. Get method takes dot delimited configuration path and returns value if any. Second returned value states if it was found and follows comma ok idiom at all.
- `(*config.Config) MustGet(context.Context, path string) any`. MustGet method is the same as Get except that it panics if the path does not exist.
- `(*config.Config) Get(context.Context, path string, files ...string) (any, bool)`. Get method takes dot delimited configuration path and returns value if any. The last parameter specifies which files to allow for searching both with or without extension. If omitted, all files will be search through. The sequence of transmitted files does not change the original order for searching. Second returned value states if it was found and follows comma ok idiom at all.
- `(*config.Config) MustGet(context.Context, path string, files ...string) any`. MustGet method is the same as Get except that it panics if the path does not exist.
- `(*config.Config) GetVaultClient() *vault.Client`. Returns vault client created and configured or provided directly by option.

#### Config options
Expand Down Expand Up @@ -223,7 +223,17 @@ func main() {
}
```

If you create correct vault secret with keys `username` and `password` and provide access then these values was printed. Managing vault auth methods, policies and secrets is out of scope.
If you create correct vault secret with keys `username` and `password` and provide access then these values was printed.

To check that certain field available direct from vault source you need to specify files argument:

```go
if password, ok := cfg.Get(ctx, "postgresql.password", "vault"); ok {
// available from vault source
}
```

Managing vault auth methods, policies and secrets is out of scope.

##### Vault Configuration

Expand Down
41 changes: 35 additions & 6 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func New(ctx context.Context, options Options) (cfg *Config, err error) {
var src cfgSource
var err error

switch source.file {
switch fileName(source.file) {
case "env":
src = envSrc
replaceEntry, err = entry.NewEnv(source)
Expand Down Expand Up @@ -260,8 +260,11 @@ type sourceValue struct {
}

// Get method takes dot delimited configuration path and returns value if any.
// The last parameter specifies which files to allow for searching both with or without extension.
// If omitted, all files will be search through.
// The sequence of transmitted files does not change the original order for searching.
// Second returned value states if it was found and follows comma ok idiom at all.
func (c *Config) Get(ctx context.Context, path string) (any, bool) {
func (c *Config) Get(ctx context.Context, path string, files ...string) (any, bool) {
if c.logger != nil && c.logger.Enabled(ctx, slog.LevelDebug) {
ctx = ContextWithLogger(ctx, c.logger)
c.logger.DebugContext(ctx, fmt.Sprintf(`trying to get "%s" field`, path))
Expand All @@ -279,7 +282,13 @@ func (c *Config) Get(ctx context.Context, path string) (any, bool) {
}
}()

v, ok := searchThroughSources(ctx, c.sources, path)
var cfgSources []configEntry = c.sources

if len(files) != 0 {
cfgSources = filterSources(ctx, c.sources, files...)
}

v, ok := searchThroughSources(ctx, cfgSources, path)

value <- sourceValue{
v: v,
Expand All @@ -296,7 +305,7 @@ func (c *Config) Get(ctx context.Context, path string) (any, bool) {
}

// MustGet method is the same as Get except that it panics if the path does not exist
func (c *Config) MustGet(ctx context.Context, path string) any {
func (c *Config) MustGet(ctx context.Context, path string, files ...string) any {
if c.logger != nil && c.logger.Enabled(ctx, slog.LevelDebug) {
ctx = ContextWithLogger(ctx, c.logger)
c.logger.DebugContext(ctx, fmt.Sprintf(`trying to get "%s" field`, path))
Expand All @@ -307,7 +316,13 @@ func (c *Config) MustGet(ctx context.Context, path string) any {
go func() {
defer close(value)

v, ok := searchThroughSources(ctx, c.sources, path)
var cfgSources []configEntry = c.sources

if len(files) != 0 {
cfgSources = filterSources(ctx, c.sources, files...)
}

v, ok := searchThroughSources(ctx, cfgSources, path)

value <- sourceValue{
v: v,
Expand All @@ -330,7 +345,7 @@ func (c *Config) MustGet(ctx context.Context, path string) any {
// Return created or directly passed vault client
func (c *Config) GetVaultClient() *vault.Client {
for _, source := range c.sources {
if source.file == "vault" {
if fileName(source.file) == "vault" {
if e, ok := source.Entry.(*entry.VaultEntry); ok {
return e.Client()
}
Expand All @@ -340,6 +355,20 @@ func (c *Config) GetVaultClient() *vault.Client {
return nil
}

func filterSources(ctx context.Context, sources []configEntry, files ...string) []configEntry {
var cfgSources []configEntry

for _, source := range sources {
if slices.ContainsFunc(files, func(file string) bool {
return source.file == file || fileName(source.file) == file
}) {
cfgSources = append(cfgSources, source)
}
}

return cfgSources
}

func searchThroughSources(ctx context.Context, sources []configEntry, path string) (any, bool) {
var v any
var ok bool
Expand Down
89 changes: 88 additions & 1 deletion pkg/config/config_test/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,10 @@ func TestConcurrent(t *testing.T) {
ctx := context.Background()

cfg, err := config.New(ctx, config.Options{
Directory: "testdata/config",
Directory: "testdata/config",
Instance: "1",
Deployment: "testing",
Hostname: "host-name",
})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -404,3 +407,87 @@ func TestConcurrent(t *testing.T) {
t.Fatal(err)
}
}

func TestGetFromCertainSource(t *testing.T) {
ctx := context.Background()

cfg, err := config.New(ctx, config.Options{
Directory: "testdata/config",
Instance: "1",
Deployment: "testing",
Hostname: "host-name",
})
if err != nil {
t.Fatal(err)
}

if v, ok := cfg.Get(ctx, "host-name-testing-1"); !ok || v != "host-name-testing-1.toml" {
t.Fatal(v, ok)
}

if v, ok := cfg.Get(ctx, "host-name-testing-1", "default"); !ok || v != "default.json" {
t.Fatal(v, ok)
}

if v, ok := cfg.Get(ctx, "host-name-testing-1", "default.json"); !ok || v != "default.json" {
t.Fatal(v, ok)
}
}

func TestGetFromCertainSourceIndifferentOrder(t *testing.T) {
ctx := context.Background()

cfg, err := config.New(ctx, config.Options{
Directory: "testdata/config",
Instance: "1",
Deployment: "testing",
Hostname: "host-name",
})
if err != nil {
t.Fatal(err)
}

if v, ok := cfg.Get(ctx, "default-1", "default.json", "default-1.json"); !ok || v != "default-1.json" {
t.Fatal(v, ok)
}

if v, ok := cfg.Get(ctx, "default-1", "default-1.json", "default.json"); !ok || v != "default-1.json" {
t.Fatal(v, ok)
}
}

func TestMustGetFromCertainSource(t *testing.T) {
t.Parallel()

defer func() {
if err := recover(); err == nil {
t.Fatal("must panic")
}
}()

ctx := context.Background()

cfg, err := config.New(ctx, config.Options{
Directory: "testdata/config",
Instance: "1",
Deployment: "testing",
Hostname: "host-name",
})
if err != nil {
t.Fatal(err)
}

if v := cfg.MustGet(ctx, "host-name-testing-1"); v != "host-name-testing-1.toml" {
t.Fatal(v)
}

if v := cfg.MustGet(ctx, "host-name-testing-1", "default"); v != "default.json" {
t.Fatal(v)
}

if v := cfg.MustGet(ctx, "host-name-testing-1", "default.json"); v != "default.json" {
t.Fatal(v)
}

cfg.MustGet(ctx, "default", "local")
}
22 changes: 11 additions & 11 deletions pkg/config/config_test/testdata/config/default-1.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"default-1": "default-1.json",
"env": "TEST_FILE_ENV",
"env": "default-1.json",
"vault": "default-1.json",
"host-name-1": "host-name-1.toml",
"host-name-testing-1": "host-name-testing-1.toml",
"host-name-testing": "host-name-testing.toml",
"host-name": "host-name.toml",
"local-1": "local-1.toml",
"local-testing-1": "local-testing-1.toml",
"local-testing": "local-testing.toml",
"local": "local.toml",
"testing-1": "testing-1.yaml",
"testing": "testing.yaml"
"host-name-1": "default-1.json",
"host-name-testing-1": "default-1.json",
"host-name-testing": "default-1.json",
"host-name": "default-1.json",
"local-1": "default-1.json",
"local-testing-1": "default-1.json",
"local-testing": "default-1.json",
"local": "default-1.json",
"testing-1": "default-1.json",
"testing": "default-1.json"
}
24 changes: 12 additions & 12 deletions pkg/config/config_test/testdata/config/default.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"default": "default.json",
"default-1": "default-1.json",
"env": "TEST_FILE_ENV",
"default-1": "default.json",
"env": "default.json",
"vault": "default.json",
"host-name-1": "host-name-1.toml",
"host-name-testing-1": "host-name-testing-1.toml",
"host-name-testing": "host-name-testing.toml",
"host-name": "host-name.toml",
"local-1": "local-1.toml",
"local-testing-1": "local-testing-1.toml",
"local-testing": "local-testing.toml",
"local": "local.toml",
"testing-1": "testing-1.yaml",
"testing": "testing.yaml"
"host-name-1": "default.json",
"host-name-testing-1": "default.json",
"host-name-testing": "default.json",
"host-name": "default.json",
"local-1": "default.json",
"local-testing-1": "default.json",
"local-testing": "default.json",
"local": "default.json",
"testing-1": "default.json",
"testing": "default.json"
}
14 changes: 7 additions & 7 deletions pkg/config/config_test/testdata/config/host-name-1.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"host-name-1" = "host-name-1.toml"
"env" = "TEST_FILE_ENV"
"env" = "host-name-1.toml"
"vault" = "host-name-1.toml"
"host-name-testing-1" = "host-name-testing-1.toml"
"host-name-testing" = "host-name-testing.toml"
"local-1" = "local-1.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing" = "local-testing.toml"
"local" = "local.toml"
"host-name-testing-1" = "host-name-1.toml"
"host-name-testing" = "host-name-1.toml"
"local-1" = "host-name-1.toml"
"local-testing-1" = "host-name-1.toml"
"local-testing" = "host-name-1.toml"
"local" = "host-name-1.toml"
10 changes: 5 additions & 5 deletions pkg/config/config_test/testdata/config/host-name-testing-1.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"host-name-testing-1" = "host-name-testing-1.toml"
"env" = "TEST_FILE_ENV"
"env" = "host-name-testing-1.toml"
"vault" = "host-name-testing-1.toml"
"local-1" = "local-1.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing" = "local-testing.toml"
"local" = "local.toml"
"local-1" = "host-name-testing-1.toml"
"local-testing-1" = "host-name-testing-1.toml"
"local-testing" = "host-name-testing-1.toml"
"local" = "host-name-testing-1.toml"
12 changes: 6 additions & 6 deletions pkg/config/config_test/testdata/config/host-name-testing.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"host-name-testing" = "host-name-testing.toml"
"env" = "TEST_FILE_ENV"
"env" = "host-name-testing.toml"
"vault" = "host-name-testing.toml"
"host-name-testing-1" = "host-name-testing-1.toml"
"local-1" = "local-1.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing" = "local-testing.toml"
"local" = "local.toml"
"host-name-testing-1" = "host-name-testing.toml"
"local-1" = "host-name-testing.toml"
"local-testing-1" = "host-name-testing.toml"
"local-testing" = "host-name-testing.toml"
"local" = "host-name-testing.toml"
16 changes: 8 additions & 8 deletions pkg/config/config_test/testdata/config/host-name.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"host-name" = "host-name.toml"
"env" = "TEST_FILE_ENV"
"env" = "host-name.toml"
"vault" = "host-name.toml"
"host-name-1" = "host-name-1.toml"
"host-name-testing-1" = "host-name-testing-1.toml"
"host-name-testing" = "host-name-testing.toml"
"local-1" = "local-1.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing" = "local-testing.toml"
"local" = "local.toml"
"host-name-1" = "host-name.toml"
"host-name-testing-1" = "host-name.toml"
"host-name-testing" = "host-name.toml"
"local-1" = "host-name.toml"
"local-testing-1" = "host-name.toml"
"local-testing" = "host-name.toml"
"local" = "host-name.toml"
6 changes: 3 additions & 3 deletions pkg/config/config_test/testdata/config/local-1.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"local-1" = "local-1.toml"
"env" = "TEST_FILE_ENV"
"env" = "local-1.toml"
"vault" = "local-1.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing" = "local-testing.toml"
"local-testing-1" = "local-1.toml"
"local-testing" = "local-1.toml"
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"local-testing-1" = "local-testing-1.toml"
"env" = "TEST_FILE_ENV"
"env" = "local-testing-1.toml"
"vault" = "local-testing-1.toml"
4 changes: 2 additions & 2 deletions pkg/config/config_test/testdata/config/local-testing.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"local-testing" = "local-testing.toml"
"env" = "TEST_FILE_ENV"
"env" = "local-testing.toml"
"vault" = "local-testing.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing-1" = "local-testing.toml"
8 changes: 4 additions & 4 deletions pkg/config/config_test/testdata/config/local.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"local" = "local.toml"
"env" = "TEST_FILE_ENV"
"env" = "local.toml"
"vault" = "local.toml"
"local-1" = "local-1.toml"
"local-testing-1" = "local-testing-1.toml"
"local-testing" = "local-testing.toml"
"local-1" = "local.toml"
"local-testing-1" = "local.toml"
"local-testing" = "local.toml"
Loading