2021-11-18 11:18:10 +00:00
// Copyright (c) HashiCorp, Inc.
2021-11-29 18:32:36 +00:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2021-07-08 15:50:25 -04:00
package base
import (
"context"
2022-11-24 19:07:37 -06:00
"fmt"
2021-07-08 15:50:25 -04:00
"sync"
"testing"
2022-03-16 17:04:07 -04:00
"github.com/hashicorp/boundary/globals"
2021-11-18 11:18:10 +00:00
"github.com/hashicorp/boundary/internal/cmd/config"
2021-07-08 15:50:25 -04:00
"github.com/hashicorp/boundary/internal/errors"
2023-09-12 08:15:34 -04:00
"github.com/hashicorp/boundary/internal/event"
2021-07-08 15:50:25 -04:00
"github.com/hashicorp/go-hclog"
2022-11-24 19:07:37 -06:00
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-kms-wrapping/v2/extras/multi"
2022-03-16 17:04:07 -04:00
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
2021-11-18 11:18:10 +00:00
"github.com/hashicorp/go-secure-stdlib/listenerutil"
2022-03-16 17:04:07 -04:00
"github.com/mitchellh/cli"
2021-07-08 15:50:25 -04:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_NewServer ( t * testing . T ) {
t . Run ( "assert-require-no-nil-fields" , func ( t * testing . T ) {
assert := assert . New ( t )
s := NewServer ( & Command {})
assert . Equal ( s . Command , & Command {})
assert . NotNil ( s . InfoKeys )
assert . NotNil ( s . Info )
assert . NotNil ( s . SecureRandomReader )
assert . NotNil ( s . ReloadFuncsLock )
assert . NotNil ( s . ReloadFuncs )
assert . NotNil ( s . StderrLock )
})
}
2022-11-24 19:07:37 -06:00
func TestServer_SetupKMSes_Purposes ( t * testing . T ) {
2022-03-16 17:04:07 -04:00
tests := [] struct {
name string
purposes [] string
wantErrContains string
}{
{
name : "nil purposes" ,
},
{
name : "empty purpose" ,
purposes : [] string { "" },
wantErrContains : "KMS block missing 'purpose'" ,
},
{
name : "unknown purpose" ,
purposes : [] string { "foobar" },
wantErrContains : "Unknown KMS purpose" ,
},
{
name : "single purpose" ,
purposes : [] string { globals . KmsPurposeRoot },
},
{
2022-06-03 13:25:58 -07:00
name : "multi purpose" ,
purposes : [] string {
2023-06-08 15:41:49 -07:00
globals . KmsPurposeRoot , globals . KmsPurposeRecovery , globals . KmsPurposeWorkerAuth , globals . KmsPurposeDownstreamWorkerAuth ,
2023-04-02 17:45:43 -04:00
globals . KmsPurposeWorkerAuthStorage , globals . KmsPurposeConfig , globals . KmsPurposeBsr ,
2022-06-03 13:25:58 -07:00
},
2022-03-16 17:04:07 -04:00
},
2022-11-24 19:07:37 -06:00
{
name : "previous root without root" ,
purposes : [] string { globals . KmsPurposePreviousRoot },
wantErrContains : fmt . Sprintf ( "KMS block contains '%s' without '%s'" , globals . KmsPurposePreviousRoot , globals . KmsPurposeRoot ),
},
{
name : "root and previous in the same stanza" ,
purposes : [] string { globals . KmsPurposeRoot , globals . KmsPurposePreviousRoot },
wantErrContains : fmt . Sprintf ( "KMS blocks with purposes '%s' and '%s' must have different key IDs" , globals . KmsPurposeRoot , globals . KmsPurposePreviousRoot ),
},
{
name : "duplicate root purposes" ,
purposes : [] string { globals . KmsPurposeRoot , globals . KmsPurposeRoot },
wantErrContains : fmt . Sprintf ( "Duplicate KMS block for purpose '%s'" , globals . KmsPurposeRoot ),
},
{
name : "duplicate previous root purposes" ,
purposes : [] string { globals . KmsPurposePreviousRoot , globals . KmsPurposePreviousRoot },
wantErrContains : fmt . Sprintf ( "Duplicate KMS block for purpose '%s'" , globals . KmsPurposePreviousRoot ),
},
{
name : "duplicate worker auth purposes" ,
purposes : [] string { globals . KmsPurposeWorkerAuth , globals . KmsPurposeWorkerAuth },
wantErrContains : fmt . Sprintf ( "Duplicate KMS block for purpose '%s'" , globals . KmsPurposeWorkerAuth ),
},
{
name : "duplicate worker auth storage purposes" ,
purposes : [] string { globals . KmsPurposeWorkerAuthStorage , globals . KmsPurposeWorkerAuthStorage },
wantErrContains : fmt . Sprintf ( "Duplicate KMS block for purpose '%s'" , globals . KmsPurposeWorkerAuthStorage ),
},
2023-04-02 17:45:43 -04:00
{
name : "duplicate bsr kms purposes" ,
purposes : [] string { globals . KmsPurposeBsr , globals . KmsPurposeBsr },
wantErrContains : fmt . Sprintf ( "Duplicate KMS block for purpose '%s'" , globals . KmsPurposeBsr ),
},
2022-11-24 19:07:37 -06:00
{
name : "duplicate recovery purposes" ,
purposes : [] string { globals . KmsPurposeRecovery , globals . KmsPurposeRecovery },
wantErrContains : fmt . Sprintf ( "Duplicate KMS block for purpose '%s'" , globals . KmsPurposeRecovery ),
},
2022-03-16 17:04:07 -04:00
}
2022-03-16 17:25:34 -04:00
logger := hclog . Default ()
serLock := new ( sync . Mutex )
2022-03-16 17:04:07 -04:00
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
conf := & configutil . SharedConfig {
Seals : [] * configutil . KMS {
{
Type : "aead" ,
Purpose : tt . purposes ,
},
},
}
2022-03-16 17:25:34 -04:00
s := NewServer ( & Command { Context : context . Background ()})
2023-06-06 17:09:08 -04:00
require . NoError ( s . SetupEventing ( s . Context , logger , serLock , "setup-kms-testing" ))
2022-03-16 17:25:34 -04:00
err := s . SetupKMSes ( s . Context , cli . NewMockUi (), & config . Config { SharedConfig : conf })
2022-03-16 17:04:07 -04:00
if tt . wantErrContains != "" {
require . Error ( err )
assert . Contains ( err . Error (), tt . wantErrContains )
return
}
require . NoError ( err )
for _ , purpose := range tt . purposes {
switch purpose {
case globals . KmsPurposeRoot :
assert . NotNil ( s . RootKms )
case globals . KmsPurposeWorkerAuth :
assert . NotNil ( s . WorkerAuthKms )
2022-06-03 13:25:58 -07:00
case globals . KmsPurposeWorkerAuthStorage :
assert . NotNil ( s . WorkerAuthStorageKms )
2022-03-16 17:04:07 -04:00
case globals . KmsPurposeRecovery :
assert . NotNil ( s . RecoveryKms )
2023-04-02 17:45:43 -04:00
case globals . KmsPurposeBsr :
assert . NotNil ( s . BsrKms )
2022-03-16 17:04:07 -04:00
}
}
})
}
}
2022-11-24 19:07:37 -06:00
func TestServer_SetupKMSes_RootMigration ( t * testing . T ) {
t . Parallel ()
t . Run ( "correctly-pools-root-and-previous" , func ( t * testing . T ) {
t . Parallel ()
assert , require := assert . New ( t ), require . New ( t )
logger := hclog . Default ()
serLock := new ( sync . Mutex )
conf := & configutil . SharedConfig {
Seals : [] * configutil . KMS {
{
Type : "aead" ,
Purpose : [] string {
globals . KmsPurposeRoot ,
},
Config : map [ string ] string {
"key_id" : "root" ,
},
},
{
Type : "aead" ,
Purpose : [] string {
globals . KmsPurposePreviousRoot ,
},
Config : map [ string ] string {
"key_id" : "previous_root" ,
},
},
},
}
s := NewServer ( & Command { Context : context . Background ()})
2023-06-06 17:09:08 -04:00
require . NoError ( s . SetupEventing ( s . Context , logger , serLock , "setup-kms-testing" ))
2022-11-24 19:07:37 -06:00
err := s . SetupKMSes ( s . Context , cli . NewMockUi (), & config . Config { SharedConfig : conf })
require . NoError ( err )
require . NotNil ( s . RootKms )
typ , err := s . RootKms . Type ( s . Context )
require . NoError ( err )
assert . Equal ( wrapping . WrapperTypePooled , typ )
// Ensure that the root is the encryptor
keyId , err := s . RootKms . KeyId ( s . Context )
require . NoError ( err )
assert . Equal ( "root" , keyId )
// Ensure that the previous root is in the wrapper too
assert . Equal ([] string { "previous_root" , "root" }, s . RootKms .( * multi . PooledWrapper ). AllKeyIds ())
})
t . Run ( "errors-on-previous-without-root" , func ( t * testing . T ) {
t . Parallel ()
require := require . New ( t )
logger := hclog . Default ()
serLock := new ( sync . Mutex )
conf := & configutil . SharedConfig {
Seals : [] * configutil . KMS {
{
Type : "aead" ,
Purpose : [] string {
globals . KmsPurposePreviousRoot ,
},
},
},
}
s := NewServer ( & Command { Context : context . Background ()})
2023-06-06 17:09:08 -04:00
require . NoError ( s . SetupEventing ( s . Context , logger , serLock , "setup-kms-testing" ))
2022-11-24 19:07:37 -06:00
err := s . SetupKMSes ( s . Context , cli . NewMockUi (), & config . Config { SharedConfig : conf })
require . Error ( err )
})
t . Run ( "errors-on-previous-and-root-with-same-key-id" , func ( t * testing . T ) {
t . Parallel ()
require := require . New ( t )
logger := hclog . Default ()
serLock := new ( sync . Mutex )
conf := & configutil . SharedConfig {
Seals : [] * configutil . KMS {
{
Type : "aead" ,
Purpose : [] string {
globals . KmsPurposeRoot ,
},
Config : map [ string ] string {
"key_id" : "root" ,
},
},
{
Type : "aead" ,
Purpose : [] string {
globals . KmsPurposePreviousRoot ,
},
Config : map [ string ] string {
"key_id" : "root" ,
},
},
},
}
s := NewServer ( & Command { Context : context . Background ()})
2023-06-06 17:09:08 -04:00
require . NoError ( s . SetupEventing ( s . Context , logger , serLock , "setup-kms-testing" ))
2022-11-24 19:07:37 -06:00
err := s . SetupKMSes ( s . Context , cli . NewMockUi (), & config . Config { SharedConfig : conf })
require . Error ( err )
})
}
2021-07-08 15:50:25 -04:00
func TestServer_SetupEventing ( t * testing . T ) {
// DO NOT run these test in parallel since they have a dependency on
// event.sysEventer
testLock := & sync . Mutex {}
testLogger := hclog . New ( & hclog . LoggerOptions {
Mutex : testLock ,
})
setTrue := true
setFalse := false
tests := [] struct {
name string
s * Server
logger hclog . Logger
lock * sync . Mutex
opt [] Option
want event . EventerConfig
wantErrMatch * errors . Template
wantErrIs error
wantErrContains string
}{
{
name : "missing-logger" ,
s : & Server {},
lock : testLock ,
wantErrMatch : errors . T ( errors . InvalidParameter ),
wantErrContains : "missing logger" ,
},
{
name : "missing-serialization-lock" ,
s : & Server {},
logger : testLogger ,
wantErrMatch : errors . T ( errors . InvalidParameter ),
wantErrContains : "missing serialization lock" ,
},
{
name : "opts-none" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
want : * event . DefaultEventerConfig (),
},
{
name : "opts-event-flags" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
opt : [] Option { WithEventFlags ( & EventFlags {
Format : event . JSONSinkFormat ,
AuditEnabled : & setTrue ,
ObservationsEnabled : & setFalse ,
2021-07-25 17:40:54 -04:00
SysEventsEnabled : & setFalse ,
2023-09-13 16:13:18 -07:00
TelemetryEnabled : & setFalse ,
2021-07-08 15:50:25 -04:00
})},
want : func () event . EventerConfig {
c := event . DefaultEventerConfig ()
c . AuditEnabled = true
c . ObservationsEnabled = false
2021-07-25 17:40:54 -04:00
c . SysEventsEnabled = false
2023-09-13 16:13:18 -07:00
c . TelemetryEnabled = false
2021-07-08 15:50:25 -04:00
return * c
}(),
},
{
name : "opts-event-flags-invalid" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
opt : [] Option { WithEventFlags ( & EventFlags {
Format : "invalid-format" ,
})},
wantErrIs : event . ErrInvalidParameter ,
wantErrContains : "not a valid sink format" ,
},
{
name : "opts-eventer-config" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
opt : [] Option { WithEventerConfig ( & event . EventerConfig {
ObservationsEnabled : false ,
SysEventsEnabled : false ,
AuditEnabled : true ,
2023-09-13 16:13:18 -07:00
TelemetryEnabled : false ,
2021-07-08 15:50:25 -04:00
})},
want : func () event . EventerConfig {
c := event . DefaultEventerConfig ()
c . AuditEnabled = true
c . ObservationsEnabled = false
c . SysEventsEnabled = false
2023-09-13 16:13:18 -07:00
c . TelemetryEnabled = false
2021-07-08 15:50:25 -04:00
return * c
}(),
},
{
name : "opts-eventer-config-invalid" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
opt : [] Option { WithEventerConfig ( & event . EventerConfig {
2021-08-30 19:02:48 -04:00
Sinks : [] * event . SinkConfig {
2021-07-08 15:50:25 -04:00
{
Format : "invalid-format" ,
},
},
})},
wantErrIs : event . ErrInvalidParameter ,
wantErrContains : "sink 0 is invalid" ,
},
2023-09-13 16:13:18 -07:00
{
name : "opts-eventer-config-observation-telemetry-invalid" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
opt : [] Option { WithEventFlags ( & EventFlags {
Format : event . JSONSinkFormat ,
AuditEnabled : & setTrue ,
ObservationsEnabled : & setFalse ,
SysEventsEnabled : & setFalse ,
TelemetryEnabled : & setTrue ,
})},
wantErrIs : event . ErrInvalidParameter ,
wantErrContains : "telemetry events require observation event to be enabled" ,
},
{
name : "opts-eventer-config-observation-on-telemetry-off" ,
s : & Server {},
logger : testLogger ,
lock : testLock ,
opt : [] Option { WithEventFlags ( & EventFlags {
Format : event . JSONSinkFormat ,
AuditEnabled : & setFalse ,
ObservationsEnabled : & setTrue ,
SysEventsEnabled : & setFalse ,
TelemetryEnabled : & setFalse ,
})},
want : func () event . EventerConfig {
c := event . DefaultEventerConfig ()
c . AuditEnabled = false
c . ObservationsEnabled = true
c . SysEventsEnabled = false
c . TelemetryEnabled = false
return * c
}(),
},
2021-07-08 15:50:25 -04:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
event . TestResetSystEventer ( t )
2023-06-06 17:09:08 -04:00
err := tt . s . SetupEventing ( context . Background (), tt . logger , tt . lock , tt . name , tt . opt ... )
2021-07-08 15:50:25 -04:00
if tt . wantErrMatch != nil || tt . wantErrIs != nil {
require . Error ( err )
assert . Nil ( tt . s . Eventer )
assert . Nil ( event . SysEventer ())
if tt . wantErrMatch != nil {
assert . Truef ( errors . Match ( tt . wantErrMatch , err ), "want %q and got %q" , tt . wantErrMatch . Code , err . Error ())
}
if tt . wantErrIs != nil {
assert . ErrorIs ( err , tt . wantErrIs )
}
if tt . wantErrContains != "" {
assert . Contains ( err . Error (), tt . wantErrContains )
}
return
}
require . NoError ( err )
assert . Equal ( tt . want , event . TestGetEventerConfig ( t , tt . s . Eventer ))
})
}
}
func TestServer_AddEventerToContext ( t * testing . T ) {
testLock := & sync . Mutex {}
testLogger := hclog . New ( & hclog . LoggerOptions {
Mutex : testLock ,
})
2021-07-25 17:40:54 -04:00
testEventer , err := event . NewEventer ( testLogger , testLock , "TestServer_AddEventerToContext" , event . EventerConfig {})
2021-07-08 15:50:25 -04:00
require . NoError ( t , err )
tests := [] struct {
name string
s Server
ctx context . Context
wantErrMatch * errors . Template
wantErrContains string
}{
{
name : "missing-eventer" ,
s : Server {},
ctx : context . Background (),
wantErrMatch : errors . T ( errors . InvalidParameter ),
wantErrContains : "missing server eventer" ,
},
{
name : "valid" ,
s : Server { Eventer : testEventer },
ctx : context . Background (),
},
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
gotCtx , err := tt . s . AddEventerToContext ( tt . ctx )
if tt . wantErrMatch != nil {
require . Error ( err )
assert . Nil ( gotCtx )
assert . Truef ( errors . Match ( tt . wantErrMatch , err ), "want %q and got %q" , tt . wantErrMatch . Code , err . Error ())
if tt . wantErrContains != "" {
assert . Contains ( err . Error (), tt . wantErrContains )
}
return
}
require . NoError ( err )
e , ok := event . EventerFromContext ( gotCtx )
require . Truef ( ok , "unable to get eventer from context" )
assert . NotNil ( e )
assert . Equal ( tt . s . Eventer , e )
})
}
}
2021-11-18 11:18:10 +00:00
func TestSetupWorkerPublicAddress ( t * testing . T ) {
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" ,
},
{
2024-09-20 11:30:27 -07:00
name : "setting public address directly with ipv4" ,
2021-11-18 11:18:10 +00:00
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" ,
},
{
2024-09-20 11:30:27 -07:00
name : "setting public address directly with ipv4:port" ,
2021-11-18 11:18:10 +00:00
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" ,
},
2024-09-20 11:30:27 -07:00
{
name : "setting public address directly with ipv6" ,
inputConfig : & config . Config {
SharedConfig : & configutil . SharedConfig {
Listeners : [] * listenerutil . ListenerConfig {},
},
Worker : & config . Worker {
PublicAddr : "[2001:4860:4860:0:0:0:0:8888]" ,
},
},
inputFlagValue : "" ,
expErr : false ,
expErrStr : "" ,
expPublicAddress : "[2001:4860:4860:0:0:0:0:8888]:9202" ,
},
{
name : "setting public address directly with ipv6:port" ,
inputConfig : & config . Config {
SharedConfig : & configutil . SharedConfig {
Listeners : [] * listenerutil . ListenerConfig {},
},
Worker : & config . Worker {
PublicAddr : "[2001:4860:4860:0:0:0:0:8888]:8080" ,
},
},
inputFlagValue : "" ,
expErr : false ,
expErrStr : "" ,
expPublicAddress : "[2001:4860:4860:0:0:0:0:8888]:8080" ,
},
{
name : "setting public address directly with abbreviated ipv6" ,
inputConfig : & config . Config {
SharedConfig : & configutil . SharedConfig {
Listeners : [] * listenerutil . ListenerConfig {},
},
Worker : & config . Worker {
PublicAddr : "[2001:4860:4860::8888]" ,
},
},
inputFlagValue : "" ,
expErr : false ,
expErrStr : "" ,
expPublicAddress : "[2001:4860:4860::8888]:9202" ,
},
{
name : "setting public address directly with abbreviated ipv6:port" ,
inputConfig : & config . Config {
SharedConfig : & configutil . SharedConfig {
Listeners : [] * listenerutil . ListenerConfig {},
},
Worker : & config . Worker {
PublicAddr : "[2001:4860:4860::8888]:8080" ,
},
},
inputFlagValue : "" ,
expErr : false ,
expErrStr : "" ,
expPublicAddress : "[2001:4860:4860::8888]:8080" ,
},
2021-11-18 11:18:10 +00:00
{
2021-11-29 18:32:36 +00:00
name : "setting public address to env var" ,
2021-11-18 11:18:10 +00:00
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" ,
},
2021-11-29 18:32:36 +00:00
{
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" ,
},
2021-11-18 11:18:10 +00:00
{
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" ,
},
2021-11-29 18:32:36 +00:00
{
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" ,
},
2021-11-18 11:18:10 +00:00
{
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 : "" ,
},
{
2021-11-29 18:32:36 +00:00
name : "using flag value to provoke error in SplitHostPort" ,
2021-11-18 11:18:10 +00:00
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 : "" ,
},
2021-11-29 18:32:36 +00:00
{
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 : "" ,
},
2021-11-18 11:18:10 +00:00
}
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 )
})
}
}