diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b98c00395..0cd93d4de3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. ### New and Improved +* config: The `max_open_connections` field for the database field in controllers now supports being set + from environment variables or a file on disk + ([PR](https://github.com/hashicorp/boundary/pull/1776)) * config: The `execution_dir` field for plugins now supports being set from environment variables or a file on disk.([PR](https://github.com/hashicorp/boundary/pull/1772)) * config: Add support for reading worker controllers off of environment diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index e877691049..4c2c6c0cbb 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -10,6 +10,7 @@ import ( "io" "io/ioutil" "reflect" + "strconv" "strings" "time" @@ -198,9 +199,10 @@ func initNameIfEmpty(name *string) error { } type Database struct { - Url string `hcl:"url"` - MigrationUrl string `hcl:"migration_url"` - MaxOpenConnections int `hcl:"max_open_connections"` + Url string `hcl:"url"` + MigrationUrl string `hcl:"migration_url"` + MaxOpenConnections int `hcl:"-"` + MaxOpenConnectionsRaw interface{} `hcl:"max_open_connections"` } type Plugins struct { @@ -338,6 +340,27 @@ func Parse(d string) (*Config, error) { } result.Controller.AuthTokenTimeToStaleDuration = t } + + if result.Controller.Database != nil { + if result.Controller.Database.MaxOpenConnectionsRaw != nil { + switch t := result.Controller.Database.MaxOpenConnectionsRaw.(type) { + case string: + maxOpenConnectionsString, err := parseutil.ParsePath(t) + if err != nil { + return nil, fmt.Errorf("Error parsing database max open connections: %w", err) + } + result.Controller.Database.MaxOpenConnections, err = strconv.Atoi(maxOpenConnectionsString) + if err != nil { + return nil, fmt.Errorf("Database max open connections value is not an int: %w", err) + } + case int: + result.Controller.Database.MaxOpenConnections = t + default: + return nil, fmt.Errorf("Database max open connections: unsupported type %q", + reflect.TypeOf(t).String()) + } + } + } } // Parse worker tags diff --git a/internal/cmd/config/config_test.go b/internal/cmd/config/config_test.go index cc57a163e0..b4bdef63c9 100644 --- a/internal/cmd/config/config_test.go +++ b/internal/cmd/config/config_test.go @@ -1052,3 +1052,96 @@ func TestPluginExecutionDir(t *testing.T) { }) } } + +func TestDatabaseMaxConnections(t *testing.T) { + tests := []struct { + name string + in string + envMaxOpenConnections string + expMaxOpenConnections int + expErr bool + expErrStr string + }{ + { + name: "Valid integer value", + in: ` + controller { + name = "example-controller" + database { + max_open_connections = 5 + } + }`, + expMaxOpenConnections: 5, + expErr: false, + }, + { + name: "Invalid value string", + in: ` + controller { + name = "example-controller" + database { + max_open_connections = "string bad" + } + }`, + expErr: true, + expErrStr: "Database max open connections value is not an int: " + + "strconv.Atoi: parsing \"string bad\": invalid syntax", + }, + { + name: "Invalid value type", + in: ` + controller { + name = "example-controller" + database { + max_open_connections = false + } + }`, + expErr: true, + expErrStr: "Database max open connections: unsupported type \"bool\"", + }, + { + name: "Valid env var", + in: ` + controller { + name = "example-controller" + database { + max_open_connections = "env://ENV_MAX_CONN" + } + }`, + expMaxOpenConnections: 8, + envMaxOpenConnections: "8", + expErr: false, + }, + { + name: "Invalid env var", + in: ` + controller { + name = "example-controller" + database { + max_open_connections = "env://ENV_MAX_CONN" + } + }`, + envMaxOpenConnections: "bogus value", + expErr: true, + expErrStr: "Database max open connections value is not an int: " + + "strconv.Atoi: parsing \"bogus value\": invalid syntax", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("ENV_MAX_CONN", tt.envMaxOpenConnections) + 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.Controller) + require.NotNil(t, c.Controller.Database) + require.Equal(t, tt.expMaxOpenConnections, c.Controller.Database.MaxOpenConnections) + }) + } +} diff --git a/website/content/docs/configuration/controller.mdx b/website/content/docs/configuration/controller.mdx index 70a80e432b..8b66781087 100644 --- a/website/content/docs/configuration/controller.mdx +++ b/website/content/docs/configuration/controller.mdx @@ -41,7 +41,9 @@ description will be read. connections that can be opened by the controller. The minimum number of connections required is 5. Setting this value to 0 will allow the controller to open as many - connections as needed. + connections as needed. This value can be a string representing the max number of connections, can refer to a file + on disk (file://) from which the number of connections will be read; or an env var (env://) from which the + number of connections will be read. Either URL can refer to a file on disk (file://) from which a URL will be read; an env var (env://) from which the URL will be read; or a direct database URL (postgres://).