Merge pull request #1731 from hashicorp/hugoamvieira-gosockaddr-template-support

feature(config): Add go-sockaddr templating support to Controller and Worker Addresses
This commit is contained in:
Hugo authored and GitHub committed 2021-11-30 17:57:55 +00:00
commit 29bdc22b41
7 files changed
+664 -14

No files matched your search

+7
View File
@@ -2,6 +2,13 @@
Canonical reference for changes, improvements, and bugfixes for Boundary.
## Next
### New and Improved
* config: Add support for go-sockaddr templates to Worker and Controller
addresses. [(PR)](https://github.com/hashicorp/boundary/pull/1731)
## 0.7.1 (2021/11/18)
### Bug Fixes
+5 -5
View File
@@ -38,9 +38,9 @@ require (
github.com/hashicorp/go-secure-stdlib/configutil v0.1.2
github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1
github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.1
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.1
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.2
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2
github.com/hashicorp/go-secure-stdlib/password v0.1.1
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1
@@ -72,7 +72,7 @@ require (
github.com/zalando/go-keyring v0.1.1
go.uber.org/atomic v1.9.0
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf
golang.org/x/tools v0.1.6
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83
@@ -100,7 +100,7 @@ require (
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Masterminds/goutils v1.1.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
@@ -135,7 +135,7 @@ require (
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
+10 -6
View File
@@ -93,8 +93,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
@@ -399,8 +400,9 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -495,12 +497,14 @@ github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1 h1:9um9R8i0+HbRHS9d64kd
github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1/go.mod h1:6RoRTSMDK2H/rKh3P/JIsk1tK8aatKTt3JyvIopi3GQ=
github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.1 h1:IJgULbAXuvWxzKFfu+Au1FUmHIJulS6N4F7Hkn+Kck0=
github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.1/go.mod h1:rf5JPE13wi+NwjgsmGkbg4b2CgHq8v7Htn/F0nDe/hg=
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.1 h1:HlTofNQN49DTzPCMVDppp+AVxMNVWaHUElpUYC0TRRE=
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.1/go.mod h1:irE9ILwhE8VooWdhHhBy0qXzOMRlHKoWoMlr31mAFCE=
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.2 h1:vx6ak5Tp3L6oJ66iPYFpp8sINOPQBIWVF0Kjn8NdLVQ=
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.2/go.mod h1:irE9ILwhE8VooWdhHhBy0qXzOMRlHKoWoMlr31mAFCE=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc=
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2 h1:Tz6v3Jb2DRnDCfifRSjYKG0m8dLdNq6bcDkB41en7nw=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 h1:SMGUnbpAcat8rIKHkBPjfv81yC46a8eCNZ2hsR2l1EI=
@@ -1194,8 +1198,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs=
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=
+623
View File
@@ -5,9 +5,12 @@ import (
"sync"
"testing"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/configutil"
"github.com/hashicorp/go-secure-stdlib/listenerutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -209,3 +212,623 @@ func TestServer_AddEventerToContext(t *testing.T) {
})
}
}
func TestSetupControllerPublicClusterAddress(t *testing.T) {
t.Parallel()
tests := []struct {
name string
inputConfig *config.Config
inputFlagValue string
stateFn func(t *testing.T)
expErr bool
expErrStr string
expPublicClusterAddress string
}{
{
name: "nil controller",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: nil,
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicClusterAddress: ":9201",
},
{
name: "setting public cluster address directly with ip",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{
PublicClusterAddr: "127.0.0.1",
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "setting public cluster address directly with ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{
PublicClusterAddr: "127.0.0.1:8080",
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:8080",
},
{
name: "setting public cluster address to env var",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{
PublicClusterAddr: "env://TEST_ENV_VAR_FOR_CONTROLLER_ADDR",
},
},
inputFlagValue: "",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_CONTROLLER_ADDR", "127.0.0.1:8080")
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:8080",
},
{
name: "setting public cluster address to env var that points to template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{
PublicClusterAddr: "env://TEST_ENV_VAR_FOR_CONTROLLER_ADDR",
},
},
inputFlagValue: "",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_CONTROLLER_ADDR", `{{ GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" | join "address" " " }}`)
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "setting public cluster address to ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{
PublicClusterAddr: `{{ GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" | join "address" " " }}`,
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "setting public cluster address to multiline ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{
PublicClusterAddr: `{{ with $local := GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" -}}
{{- $local | join "address" " " -}}
{{- end }}`,
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "using flag value with ip only",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "127.0.0.1",
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "using flag value with ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "127.0.0.1:8080",
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:8080",
},
{
name: "using flag value with ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: `{{ GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" | join "address" " " }}`,
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "using flag value with multiline ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: `{{ with $local := GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" -}}
{{- $local | join "address" " " -}}
{{- end }}`,
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "using flag value to point to env var with ip only",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "env://TEST_ENV_VAR_FOR_CONTROLLER_ADDR",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_CONTROLLER_ADDR", "127.0.0.1")
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "using flag value to point to env var with ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "env://TEST_ENV_VAR_FOR_CONTROLLER_ADDR",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_CONTROLLER_ADDR", "127.0.0.1:8080")
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:8080",
},
{
name: "read address from listeners ip only",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{
{Purpose: []string{"cluster"}, Address: "127.0.0.1"},
},
},
Controller: &config.Controller{},
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:9201",
},
{
name: "read address from listeners ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{
{Purpose: []string{"cluster"}, Address: "127.0.0.1:8080"},
},
},
Controller: &config.Controller{},
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: "127.0.0.1:8080",
},
{
name: "read address from listeners is ignored on different purpose",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{
{Purpose: []string{"somethingelse"}, Address: "127.0.0.1:8080"},
},
},
Controller: &config.Controller{},
},
expErr: false,
expErrStr: "",
expPublicClusterAddress: ":9201",
},
{
name: "using flag value to point to nonexistent file",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "file://this_doesnt_exist_for_sure",
expErr: true,
expErrStr: "Error parsing public cluster addr: error reading file at file://this_doesnt_exist_for_sure: open this_doesnt_exist_for_sure: no such file or directory",
expPublicClusterAddress: "",
},
{
name: "using flag value to provoke error in SplitHostPort",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "abc::123",
expErr: true,
expErrStr: "Error splitting public cluster adddress host/port: address abc::123: too many colons in address",
expPublicClusterAddress: "",
},
{
name: "bad ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Controller: &config.Controller{},
},
inputFlagValue: "{{ somethingthatdoesntexist }}",
expErr: true,
expErrStr: "Error parsing IP template on controller public cluster addr: unable to parse address template \"{{ somethingthatdoesntexist }}\": unable to parse template \"{{ somethingthatdoesntexist }}\": template: sockaddr.Parse:1: function \"somethingthatdoesntexist\" not defined",
expPublicClusterAddress: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.stateFn != nil {
tt.stateFn(t)
}
s := Server{}
err := s.SetupControllerPublicClusterAddress(tt.inputConfig, tt.inputFlagValue)
if tt.expErr {
require.EqualError(t, err, tt.expErrStr)
return
}
require.NoError(t, err)
require.NotNil(t, tt.inputConfig.Controller)
require.Equal(t, tt.expPublicClusterAddress, tt.inputConfig.Controller.PublicClusterAddr)
})
}
}
func TestSetupWorkerPublicAddress(t *testing.T) {
t.Parallel()
tests := []struct {
name string
inputConfig *config.Config
inputFlagValue string
stateFn func(t *testing.T)
expErr bool
expErrStr string
expPublicAddress string
}{
{
name: "nil worker",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: nil,
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicAddress: ":9202",
},
{
name: "setting public address directly with ip",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{
PublicAddr: "127.0.0.1",
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "setting public address directly with ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{
PublicAddr: "127.0.0.1:8080",
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:8080",
},
{
name: "setting public address to env var",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{
PublicAddr: "env://TEST_ENV_VAR_FOR_WORKER_ADDR",
},
},
inputFlagValue: "",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_WORKER_ADDR", "127.0.0.1:8080")
},
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:8080",
},
{
name: "setting public address to env var that points to template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{
PublicAddr: "env://TEST_ENV_VAR_FOR_WORKER_ADDR",
},
},
inputFlagValue: "",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_WORKER_ADDR", `{{ GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" | join "address" " " }}`)
},
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "setting public address to ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{
PublicAddr: `{{ GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" | join "address" " " }}`,
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "setting public address to multiline ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{
PublicAddr: `{{ with $local := GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" -}}
{{- $local | join "address" " " -}}
{{- end }}`,
},
},
inputFlagValue: "",
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "using flag value with ip only",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "127.0.0.1",
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "using flag value with ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "127.0.0.1:8080",
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:8080",
},
{
name: "using flag value to point to env var with ip only",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "env://TEST_ENV_VAR_FOR_WORKER_ADDR",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_WORKER_ADDR", "127.0.0.1")
},
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "using flag value to point to env var with ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "env://TEST_ENV_VAR_FOR_WORKER_ADDR",
stateFn: func(t *testing.T) {
t.Setenv("TEST_ENV_VAR_FOR_WORKER_ADDR", "127.0.0.1:8080")
},
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:8080",
},
{
name: "using flag value with ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: `{{ GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" | join "address" " " }}`,
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "using flag value with multiline ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: `{{ with $local := GetAllInterfaces | include "flags" "loopback" | include "type" "IPV4" -}}
{{- $local | join "address" " " -}}
{{- end }}`,
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "read address from listeners ip only",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{
{Purpose: []string{"proxy"}, Address: "127.0.0.1"},
},
},
Worker: &config.Worker{},
},
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:9202",
},
{
name: "read address from listeners ip:port",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{
{Purpose: []string{"proxy"}, Address: "127.0.0.1:8080"},
},
},
Worker: &config.Worker{},
},
expErr: false,
expErrStr: "",
expPublicAddress: "127.0.0.1:8080",
},
{
name: "read address from listeners is ignored on different purpose",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{
{Purpose: []string{"somethingelse"}, Address: "127.0.0.1:8080"},
},
},
Worker: &config.Worker{},
},
expErr: false,
expErrStr: "",
expPublicAddress: ":9202",
},
{
name: "using flag value to point to nonexistent file",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "file://this_doesnt_exist_for_sure",
expErr: true,
expErrStr: "Error parsing public addr: error reading file at file://this_doesnt_exist_for_sure: open this_doesnt_exist_for_sure: no such file or directory",
expPublicAddress: "",
},
{
name: "using flag value to provoke error in SplitHostPort",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "abc::123",
expErr: true,
expErrStr: "Error splitting public adddress host/port: address abc::123: too many colons in address",
expPublicAddress: "",
},
{
name: "bad ip template",
inputConfig: &config.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*listenerutil.ListenerConfig{},
},
Worker: &config.Worker{},
},
inputFlagValue: "{{ somethingthatdoesntexist }}",
expErr: true,
expErrStr: "Error parsing IP template on worker public addr: unable to parse address template \"{{ somethingthatdoesntexist }}\": unable to parse template \"{{ somethingthatdoesntexist }}\": template: sockaddr.Parse:1: function \"somethingthatdoesntexist\" not defined",
expPublicAddress: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.stateFn != nil {
tt.stateFn(t)
}
s := Server{}
err := s.SetupWorkerPublicAddress(tt.inputConfig, tt.inputFlagValue)
if tt.expErr {
require.EqualError(t, err, tt.expErrStr)
return
}
require.NoError(t, err)
require.NotNil(t, tt.inputConfig.Worker)
require.Equal(t, tt.expPublicAddress, tt.inputConfig.Worker.PublicAddr)
})
}
}
+13
View File
@@ -34,6 +34,7 @@ import (
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/configutil"
"github.com/hashicorp/go-secure-stdlib/gatedwriter"
"github.com/hashicorp/go-secure-stdlib/listenerutil"
"github.com/hashicorp/go-secure-stdlib/mlock"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/reloadutil"
@@ -642,7 +643,13 @@ func (b *Server) SetupControllerPublicClusterAddress(conf *config.Config, flagVa
if err != nil && !errors.Is(err, parseutil.ErrNotAUrl) {
return fmt.Errorf("Error parsing public cluster addr: %w", err)
}
conf.Controller.PublicClusterAddr, err = listenerutil.ParseSingleIPTemplate(conf.Controller.PublicClusterAddr)
if err != nil {
return fmt.Errorf("Error parsing IP template on controller public cluster addr: %w", err)
}
}
host, port, err := net.SplitHostPort(conf.Controller.PublicClusterAddr)
if err != nil {
if strings.Contains(err.Error(), "missing port") {
@@ -679,7 +686,13 @@ func (b *Server) SetupWorkerPublicAddress(conf *config.Config, flagValue string)
if err != nil && !errors.Is(err, parseutil.ErrNotAUrl) {
return fmt.Errorf("Error parsing public addr: %w", err)
}
conf.Worker.PublicAddr, err = listenerutil.ParseSingleIPTemplate(conf.Worker.PublicAddr)
if err != nil {
return fmt.Errorf("Error parsing IP template on worker public addr: %w", err)
}
}
host, port, err := net.SplitHostPort(conf.Worker.PublicAddr)
if err != nil {
if strings.Contains(err.Error(), "missing port") {
@@ -51,8 +51,8 @@ controller {
`cluster` purpose. This is especially useful for cloud environments that do not
bind a publicly accessible IP to a NIC on the host directly, such as an Amazon
EIP. This value can be a direct address string, can refer to a file on disk (file://)
from which an address will be read; or an env var (env://) from which the
address will be read.
from which an address will be read; an env var (env://) from which the
address will be read; or a [go-sockaddr template](https://godoc.org/github.com/hashicorp/go-sockaddr/template).
- `auth_token_time_to_live` - Maximum time to live (TTL) for all auth tokens globally (pertains
to all tokens from all auth methods). Valid time units are anything specified by Golang's
@@ -28,7 +28,10 @@ worker {
at which the worker can be reached _by clients for proxying_. This defaults to
the address of the listener marked for `proxy` purpose. This is especially
useful for cloud environments that do not bind a publicly accessible IP to a NIC
on the host directly, such as an Amazon EIP.
on the host directly, such as an Amazon EIP. This value can be a direct address string,
can refer to a file on disk (file://) from which an address will be read;
an env var (env://) from which the address will be read;
or a [go-sockaddr template](https://godoc.org/github.com/hashicorp/go-sockaddr/template).
- `controllers` - A list of hosts/IP addresses and optionally ports for reaching
controllers. The port will default to :9201 if not specified.