This feature allows the user to set the `tags` field to a string that points to either an environment variable or file. We then dynamically pull out the value and parse it into the config. This can also be done at the keys level, where you set your keys directly in Boundary's config file, but point the values to env/file.
813 lines
18 KiB
Go
813 lines
18 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/internal/observability/event"
|
|
"github.com/hashicorp/go-secure-stdlib/configutil"
|
|
"github.com/hashicorp/go-secure-stdlib/listenerutil"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestDevController(t *testing.T) {
|
|
actual, err := DevController()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
truePointer := new(bool)
|
|
*truePointer = true
|
|
exp := &Config{
|
|
Eventing: event.DefaultEventerConfig(),
|
|
SharedConfig: &configutil.SharedConfig{
|
|
DisableMlock: true,
|
|
Listeners: []*listenerutil.ListenerConfig{
|
|
{
|
|
Type: "tcp",
|
|
Purpose: []string{"api"},
|
|
TLSDisable: true,
|
|
CorsEnabled: truePointer,
|
|
CorsAllowedOrigins: []string{"*"},
|
|
},
|
|
{
|
|
Type: "tcp",
|
|
Purpose: []string{"cluster"},
|
|
},
|
|
},
|
|
Seals: []*configutil.KMS{
|
|
{
|
|
Type: "aead",
|
|
Purpose: []string{"root"},
|
|
Config: map[string]string{
|
|
"aead_type": "aes-gcm",
|
|
"key_id": "global_root",
|
|
},
|
|
},
|
|
{
|
|
Type: "aead",
|
|
Purpose: []string{"worker-auth"},
|
|
Config: map[string]string{
|
|
"aead_type": "aes-gcm",
|
|
"key_id": "global_worker-auth",
|
|
},
|
|
},
|
|
{
|
|
Type: "aead",
|
|
Purpose: []string{"recovery"},
|
|
Config: map[string]string{
|
|
"aead_type": "aes-gcm",
|
|
"key_id": "global_recovery",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Controller: &Controller{
|
|
Name: "dev-controller",
|
|
Description: "A default controller created in dev mode",
|
|
},
|
|
DevController: true,
|
|
}
|
|
|
|
exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig
|
|
exp.Listeners[1].RawConfig = actual.Listeners[1].RawConfig
|
|
exp.Seals[0].Config["key"] = actual.Seals[0].Config["key"]
|
|
exp.Seals[1].Config["key"] = actual.Seals[1].Config["key"]
|
|
exp.Seals[2].Config["key"] = actual.Seals[2].Config["key"]
|
|
exp.DevControllerKey = actual.Seals[0].Config["key"]
|
|
exp.DevWorkerAuthKey = actual.Seals[1].Config["key"]
|
|
exp.DevRecoveryKey = actual.Seals[2].Config["key"]
|
|
|
|
assert.Equal(t, exp, actual)
|
|
|
|
// Do some CORS-specific testing
|
|
{
|
|
// CORS disabled
|
|
conf := `
|
|
listener "tcp" {
|
|
purpose = "api"
|
|
cors_enabled = false
|
|
}
|
|
`
|
|
actual, err = Parse(conf)
|
|
assert.NoError(t, err)
|
|
l0 := actual.Listeners[0]
|
|
assert.False(t, *l0.CorsEnabled)
|
|
assert.Empty(t, l0.CorsAllowedHeaders)
|
|
|
|
// Enabled with a wildcard
|
|
conf = `
|
|
listener "tcp" {
|
|
purpose = "api"
|
|
cors_enabled = true
|
|
cors_allowed_origins = ["*"]
|
|
}
|
|
`
|
|
actual, err = Parse(conf)
|
|
assert.NoError(t, err)
|
|
l0 = actual.Listeners[0]
|
|
assert.True(t, *l0.CorsEnabled)
|
|
assert.Equal(t, []string{"*"}, l0.CorsAllowedOrigins)
|
|
assert.Nil(t, l0.CorsDisableDefaultAllowedOriginValues)
|
|
|
|
// Disabled, default behavior
|
|
conf = `
|
|
listener "tcp" {
|
|
purpose = "api"
|
|
}
|
|
`
|
|
actual, err = Parse(conf)
|
|
assert.NoError(t, err)
|
|
l0 = actual.Listeners[0]
|
|
assert.True(t, *l0.CorsEnabled)
|
|
assert.Equal(t, []string{"*"}, l0.CorsAllowedOrigins)
|
|
assert.Nil(t, l0.CorsDisableDefaultAllowedOriginValues)
|
|
|
|
// Disabled, default behavior
|
|
conf = `
|
|
listener "tcp" {
|
|
purpose = "api"
|
|
cors_disable_default_allowed_origin_values = true
|
|
}
|
|
`
|
|
actual, err = Parse(conf)
|
|
assert.NoError(t, err)
|
|
l0 = actual.Listeners[0]
|
|
assert.Nil(t, l0.CorsEnabled)
|
|
assert.Empty(t, l0.CorsAllowedOrigins)
|
|
assert.True(t, *l0.CorsDisableDefaultAllowedOriginValues)
|
|
}
|
|
|
|
// Test plugins block
|
|
{
|
|
// CORS disabled
|
|
conf := `
|
|
plugins {
|
|
execution_dir = "/tmp/foobar"
|
|
}
|
|
`
|
|
actual, err = Parse(conf)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, actual.Plugins.ExecutionDir, "/tmp/foobar")
|
|
}
|
|
}
|
|
|
|
func TestDevWorker(t *testing.T) {
|
|
actual, err := DevWorker()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
exp := &Config{
|
|
Eventing: event.DefaultEventerConfig(),
|
|
SharedConfig: &configutil.SharedConfig{
|
|
DisableMlock: true,
|
|
Listeners: []*listenerutil.ListenerConfig{
|
|
{
|
|
Type: "tcp",
|
|
Purpose: []string{"proxy"},
|
|
},
|
|
},
|
|
},
|
|
Worker: &Worker{
|
|
Name: "dev-worker",
|
|
Description: "A default worker created in dev mode",
|
|
Controllers: []string{"127.0.0.1"},
|
|
Tags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
},
|
|
},
|
|
}
|
|
|
|
exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig
|
|
exp.Worker.TagsRaw = actual.Worker.TagsRaw
|
|
assert.Equal(t, exp, actual)
|
|
|
|
// Redo it with key=value syntax for tags
|
|
devWorkerKeyValueConfig := `
|
|
listener "tcp" {
|
|
purpose = "proxy"
|
|
}
|
|
|
|
worker {
|
|
name = "dev-worker"
|
|
description = "A default worker created in dev mode"
|
|
controllers = ["127.0.0.1"]
|
|
tags = ["type=dev", "type=local"]
|
|
}
|
|
`
|
|
|
|
actual, err = Parse(devConfig + devWorkerKeyValueConfig)
|
|
assert.NoError(t, err)
|
|
exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig
|
|
exp.Worker.TagsRaw = actual.Worker.TagsRaw
|
|
assert.Equal(t, exp, actual)
|
|
|
|
// Handle when there is a singular value not indicated as a slice
|
|
devWorkerKeyValueConfig = `
|
|
listener "tcp" {
|
|
purpose = "proxy"
|
|
}
|
|
|
|
worker {
|
|
name = "dev-worker"
|
|
description = "A default worker created in dev mode"
|
|
controllers = ["127.0.0.1"]
|
|
tags {
|
|
type = "local"
|
|
}
|
|
}
|
|
`
|
|
|
|
actual, err = Parse(devConfig + devWorkerKeyValueConfig)
|
|
assert.NoError(t, err)
|
|
exp.Listeners[0].RawConfig = actual.Listeners[0].RawConfig
|
|
exp.Worker.TagsRaw = actual.Worker.TagsRaw
|
|
prevTags := exp.Worker.Tags
|
|
exp.Worker.Tags = map[string][]string{"type": {"local"}}
|
|
assert.Equal(t, exp, actual)
|
|
exp.Worker.Tags = prevTags
|
|
|
|
// Redo it with non-lower-cased keys
|
|
devWorkerKeyValueConfig = `
|
|
listener "tcp" {
|
|
purpose = "proxy"
|
|
}
|
|
|
|
worker {
|
|
name = "dev-worker"
|
|
description = "A default worker created in dev mode"
|
|
controllers = ["127.0.0.1"]
|
|
tags = ["tyPe=dev", "type=local"]
|
|
}
|
|
`
|
|
|
|
_, err = Parse(devConfig + devWorkerKeyValueConfig)
|
|
assert.Error(t, err)
|
|
|
|
// Redo it with non-lower-cased values
|
|
devWorkerKeyValueConfig = `
|
|
listener "tcp" {
|
|
purpose = "proxy"
|
|
}
|
|
|
|
worker {
|
|
name = "dev-worker"
|
|
description = "A default worker created in dev mode"
|
|
controllers = ["127.0.0.1"]
|
|
tags = ["type=dev", "type=loCal"]
|
|
}
|
|
`
|
|
|
|
_, err = Parse(devConfig + devWorkerKeyValueConfig)
|
|
assert.Error(t, err)
|
|
|
|
// Redo with non-printable characters to validate the strutil function
|
|
devWorkerKeyValueConfig = `
|
|
listener "tcp" {
|
|
purpose = "proxy"
|
|
}
|
|
|
|
worker {
|
|
name = "dev-work\u0000er"
|
|
description = "A default worker created in dev mode"
|
|
controllers = ["127.0.0.1"]
|
|
tags = ["type=dev", "type=local"]
|
|
}
|
|
`
|
|
|
|
_, err = Parse(devConfig + devWorkerKeyValueConfig)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestParsingName(t *testing.T) {
|
|
t.Parallel()
|
|
config := `
|
|
controller {
|
|
name = "%s"
|
|
}
|
|
worker {
|
|
name = "%s"
|
|
}
|
|
`
|
|
controllerEnv := "FOOENV"
|
|
workerEnv := "BARENV"
|
|
cases := []struct {
|
|
name string
|
|
templateController string
|
|
templateWorker string
|
|
envController string
|
|
envWorker string
|
|
expectedController string
|
|
expectedWorker string
|
|
}{
|
|
{
|
|
name: "no env",
|
|
templateController: "foobar",
|
|
templateWorker: "barfoo",
|
|
expectedController: "foobar",
|
|
expectedWorker: "barfoo",
|
|
},
|
|
{
|
|
name: "env",
|
|
templateController: fmt.Sprintf("env://%s", controllerEnv),
|
|
templateWorker: fmt.Sprintf("env://%s", workerEnv),
|
|
envController: "foobar2",
|
|
envWorker: "barfoo2",
|
|
expectedController: "foobar2",
|
|
expectedWorker: "barfoo2",
|
|
},
|
|
}
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.envController != "" {
|
|
os.Setenv(controllerEnv, tt.envController)
|
|
}
|
|
if tt.envWorker != "" {
|
|
os.Setenv(workerEnv, tt.envWorker)
|
|
}
|
|
out, err := Parse(fmt.Sprintf(config, tt.templateController, tt.templateWorker))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.expectedController, out.Controller.Name)
|
|
assert.Equal(t, tt.expectedWorker, out.Worker.Name)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWorkerTags(t *testing.T) {
|
|
defaultStateFn := func(t *testing.T, tags string) {
|
|
t.Setenv("BOUNDARY_WORKER_TAGS", tags)
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
stateFn func(t *testing.T, tags string)
|
|
actualTags string
|
|
expWorkerTags map[string][]string
|
|
expErr bool
|
|
expErrStr string
|
|
}{
|
|
{
|
|
name: "tags in HCL",
|
|
in: `
|
|
worker {
|
|
tags {
|
|
type = ["dev", "local"]
|
|
typetwo = "devtwo"
|
|
}
|
|
}`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
"typetwo": {"devtwo"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "tags in HCL key=value",
|
|
in: `
|
|
worker {
|
|
tags = ["type=dev", "type=local", "typetwo=devtwo"]
|
|
}
|
|
`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
"typetwo": {"devtwo"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "no tags",
|
|
in: `
|
|
worker {
|
|
name = "testworker"
|
|
}
|
|
`,
|
|
expWorkerTags: nil,
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "empty tags",
|
|
in: `
|
|
worker {
|
|
name = "testworker"
|
|
tags = {}
|
|
}
|
|
`,
|
|
expWorkerTags: map[string][]string{},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "empty tags 2",
|
|
in: `
|
|
worker {
|
|
name = "testworker"
|
|
tags = []
|
|
}
|
|
`,
|
|
expWorkerTags: map[string][]string{},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "empty str",
|
|
in: `
|
|
worker {
|
|
tags = ""
|
|
}`,
|
|
expWorkerTags: map[string][]string{},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "empty env var",
|
|
in: `
|
|
worker {
|
|
tags = "env://BOUNDARY_WORKER_TAGS"
|
|
}`,
|
|
expWorkerTags: map[string][]string{},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "not a url - entire tags block",
|
|
in: `
|
|
worker {
|
|
tags = "\x00"
|
|
}`,
|
|
expWorkerTags: map[string][]string{},
|
|
expErr: true,
|
|
expErrStr: `Error parsing worker tags: error parsing url ("parse \"\\x00\": net/url: invalid control character in URL"): not a url`,
|
|
},
|
|
{
|
|
name: "not a url - key's value set to string",
|
|
in: `
|
|
worker {
|
|
tags {
|
|
type = "\x00"
|
|
}
|
|
}
|
|
`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"\x00"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "one tag key",
|
|
in: `
|
|
worker {
|
|
tags = "env://BOUNDARY_WORKER_TAGS"
|
|
}`,
|
|
stateFn: defaultStateFn,
|
|
actualTags: `type = ["dev", "local"]`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "multiple tag keys",
|
|
in: `
|
|
worker {
|
|
tags = "env://BOUNDARY_WORKER_TAGS"
|
|
}`,
|
|
stateFn: defaultStateFn,
|
|
actualTags: `
|
|
type = ["dev", "local"]
|
|
typetwo = ["devtwo", "localtwo"]
|
|
`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
"typetwo": {"devtwo", "localtwo"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "json tags - entire tags block",
|
|
in: `
|
|
worker {
|
|
tags = "env://BOUNDARY_WORKER_TAGS"
|
|
}`,
|
|
stateFn: defaultStateFn,
|
|
actualTags: `
|
|
{
|
|
"type": ["dev", "local"],
|
|
"typetwo": ["devtwo", "localtwo"]
|
|
}
|
|
`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
"typetwo": {"devtwo", "localtwo"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "json tags - keys specified in the HCL file, values point to env/file",
|
|
in: `
|
|
worker {
|
|
tags = {
|
|
type = "env://BOUNDARY_WORKER_TAGS"
|
|
typetwo = "env://BOUNDARY_WORKER_TAGS_TWO"
|
|
}
|
|
}`,
|
|
stateFn: func(t *testing.T, tags string) {
|
|
defaultStateFn(t, tags)
|
|
t.Setenv("BOUNDARY_WORKER_TAGS_TWO", `["devtwo", "localtwo"]`)
|
|
},
|
|
actualTags: `["dev","local"]`,
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
"typetwo": {"devtwo", "localtwo"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "json tags - mix n' match",
|
|
in: `
|
|
worker {
|
|
name = "web-prod-us-east-1"
|
|
tags {
|
|
type = "env://BOUNDARY_WORKER_TYPE_TAGS"
|
|
typetwo = "file://type_two_tags.json"
|
|
typethree = ["devthree", "localthree"]
|
|
}
|
|
}
|
|
`,
|
|
stateFn: func(t *testing.T, tags string) {
|
|
workerTypeTags := `["dev", "local"]`
|
|
t.Setenv("BOUNDARY_WORKER_TYPE_TAGS", workerTypeTags)
|
|
|
|
filepath := "./type_two_tags.json"
|
|
err := os.WriteFile(filepath, []byte(`["devtwo", "localtwo"]`), 0o666)
|
|
require.NoError(t, err)
|
|
|
|
t.Cleanup(func() {
|
|
err := os.Remove(filepath)
|
|
require.NoError(t, err)
|
|
})
|
|
},
|
|
expWorkerTags: map[string][]string{
|
|
"type": {"dev", "local"},
|
|
"typetwo": {"devtwo", "localtwo"},
|
|
"typethree": {"devthree", "localthree"},
|
|
},
|
|
expErr: false,
|
|
},
|
|
{
|
|
name: "bad json tags",
|
|
in: `
|
|
worker {
|
|
tags = {
|
|
type = "env://BOUNDARY_WORKER_TAGS"
|
|
typetwo = "env://BOUNDARY_WORKER_TAGS"
|
|
}
|
|
}`,
|
|
stateFn: defaultStateFn,
|
|
actualTags: `
|
|
{
|
|
"type": ["dev", "local"],
|
|
"typetwo": ["devtwo", "localtwo"]
|
|
}
|
|
`,
|
|
expWorkerTags: nil,
|
|
expErr: true,
|
|
expErrStr: "Error unmarshalling env var/file contents: json: cannot unmarshal object into Go value of type []string",
|
|
},
|
|
{
|
|
name: "no clean mapping to internal structures",
|
|
in: `
|
|
worker {
|
|
tags = "env://BOUNDARY_WORKER_TAGS"
|
|
}`,
|
|
stateFn: defaultStateFn,
|
|
actualTags: `
|
|
worker {
|
|
tags {
|
|
type = "indeed"
|
|
}
|
|
}
|
|
`,
|
|
expErr: true,
|
|
expErrStr: "Error decoding the worker's tags: 1 error(s) decoding:\n\n* '[0][worker][0]' expected type 'string', got unconvertible type 'map[string]interface {}', value: 'map[tags:[map[type:indeed]]]'",
|
|
},
|
|
{
|
|
name: "not HCL",
|
|
in: `worker {
|
|
tags = "env://BOUNDARY_WORKER_TAGS"
|
|
}`,
|
|
stateFn: defaultStateFn,
|
|
actualTags: `not_hcl`,
|
|
expErr: true,
|
|
expErrStr: "Error decoding raw worker tags: At 1:9: key 'not_hcl' expected start of object ('{') or assignment ('=')",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.stateFn != nil {
|
|
tt.stateFn(t, tt.actualTags)
|
|
}
|
|
|
|
c, err := Parse(tt.in)
|
|
if tt.expErr {
|
|
require.EqualError(t, err, tt.expErrStr)
|
|
require.Nil(t, c)
|
|
return
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, c)
|
|
require.NotNil(t, c.Worker)
|
|
require.Equal(t, tt.expWorkerTags, c.Worker.Tags)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestController_EventingConfig(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
config []string
|
|
wantEventerConfig *event.EventerConfig
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "default",
|
|
wantEventerConfig: event.DefaultEventerConfig(),
|
|
},
|
|
{
|
|
name: "audit-enabled",
|
|
config: []string{`
|
|
events {
|
|
audit_enabled = true
|
|
}
|
|
`},
|
|
wantEventerConfig: &event.EventerConfig{
|
|
AuditEnabled: true,
|
|
ObservationsEnabled: false,
|
|
Sinks: []*event.SinkConfig{
|
|
event.DefaultSink(),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "observations-enabled",
|
|
config: []string{`
|
|
events {
|
|
observations_enabled = true
|
|
}
|
|
`},
|
|
wantEventerConfig: &event.EventerConfig{
|
|
AuditEnabled: false,
|
|
ObservationsEnabled: true,
|
|
Sinks: []*event.SinkConfig{
|
|
event.DefaultSink(),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "no-sink-type-determined",
|
|
config: []string{
|
|
`events {
|
|
audit_enabled = false
|
|
observations_enabled = true
|
|
sink {
|
|
format = "cloudevents-json"
|
|
name = "configured-sink"
|
|
event_types = [ "audit", "observation" ]
|
|
}
|
|
}`,
|
|
},
|
|
wantErr: `error parsing "events": sink type could not be determined`,
|
|
},
|
|
{
|
|
name: "sinks-configured",
|
|
config: []string{
|
|
`events {
|
|
audit_enabled = false
|
|
observations_enabled = true
|
|
sink {
|
|
type = "file"
|
|
format = "cloudevents-json"
|
|
name = "configured-sink"
|
|
event_types = [ "audit", "observation" ]
|
|
file {
|
|
file_name = "file-name"
|
|
rotate_duration = "2m"
|
|
}
|
|
}
|
|
sink {
|
|
type = "stderr"
|
|
format = "hclog-text"
|
|
name = "stderr-sink"
|
|
event_types = [ "error" ]
|
|
}
|
|
}`,
|
|
`events {
|
|
audit_enabled = false
|
|
observations_enabled = true
|
|
sink "file" {
|
|
format = "cloudevents-json"
|
|
name = "configured-sink"
|
|
event_types = [ "audit", "observation" ]
|
|
file {
|
|
file_name = "file-name"
|
|
rotate_duration = "2m"
|
|
}
|
|
}
|
|
sink "stderr" {
|
|
format = "hclog-text"
|
|
name = "stderr-sink"
|
|
event_types = [ "error" ]
|
|
}
|
|
}`,
|
|
`events {
|
|
audit_enabled = false
|
|
observations_enabled = true
|
|
sink {
|
|
format = "cloudevents-json"
|
|
name = "configured-sink"
|
|
event_types = [ "audit", "observation" ]
|
|
file {
|
|
file_name = "file-name"
|
|
rotate_duration = "2m"
|
|
}
|
|
}
|
|
sink {
|
|
format = "hclog-text"
|
|
name = "stderr-sink"
|
|
event_types = [ "error" ]
|
|
stderr = {}
|
|
}
|
|
}`,
|
|
`{
|
|
"events": {
|
|
"audit_enabled": false,
|
|
"observations_enabled": true,
|
|
"sink": [
|
|
{
|
|
"type": "file",
|
|
"format": "cloudevents-json",
|
|
"name": "configured-sink",
|
|
"event_types": ["audit", "observation"],
|
|
"file": {
|
|
"file_name": "file-name",
|
|
"rotate_duration": "2m"
|
|
}
|
|
},
|
|
{
|
|
"format": "hclog-text",
|
|
"name": "stderr-sink",
|
|
"event_types": ["error"],
|
|
"stderr": {}
|
|
}
|
|
]
|
|
}
|
|
}`,
|
|
},
|
|
wantEventerConfig: &event.EventerConfig{
|
|
AuditEnabled: false,
|
|
ObservationsEnabled: true,
|
|
Sinks: []*event.SinkConfig{
|
|
{
|
|
Type: "file",
|
|
Name: "configured-sink",
|
|
Format: "cloudevents-json",
|
|
EventTypes: []event.Type{"audit", "observation"},
|
|
FileConfig: &event.FileSinkTypeConfig{
|
|
FileName: "file-name",
|
|
RotateDurationHCL: "2m",
|
|
RotateDuration: 2 * time.Minute,
|
|
},
|
|
},
|
|
{
|
|
Type: "stderr",
|
|
Name: "stderr-sink",
|
|
Format: "hclog-text",
|
|
EventTypes: []event.Type{"error"},
|
|
StderrConfig: &event.StderrSinkTypeConfig{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
for i, conf := range tt.config {
|
|
c, err := Parse(conf)
|
|
if tt.wantErr != "" {
|
|
require.Error(err)
|
|
assert.Empty(c)
|
|
assert.Equal(tt.wantErr, err.Error(), "config %d want %q and got %q", i, tt.wantErr, err.Error())
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.NotEmpty(c)
|
|
assert.Equal(tt.wantEventerConfig, c.Eventing)
|
|
}
|
|
})
|
|
}
|
|
}
|