From 1e4e7a2815e6be6469197bb4dab17f8960e002ef Mon Sep 17 00:00:00 2001 From: Rob Holland Date: Mon, 8 Jul 2024 14:16:16 +0100 Subject: [PATCH 1/4] Add support for templating in configs. Amongst other use cases, this avoids the need to use dockerize in container deployments, making it much easier to build more secure images which do not need write access to the filesystem. --- common/config/loader.go | 19 ++++++++++++++++++- common/config/loader_test.go | 20 ++++++++++---------- go.mod | 9 +++++++++ go.sum | 26 ++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/common/config/loader.go b/common/config/loader.go index aeefb87a272..a74a42bf772 100644 --- a/common/config/loader.go +++ b/common/config/loader.go @@ -25,10 +25,13 @@ package config import ( + "bytes" "fmt" stdlog "log" "os" + "text/template" + "github.com/Masterminds/sprig/v3" "gopkg.in/validator.v2" "gopkg.in/yaml.v3" ) @@ -90,6 +93,8 @@ func Load(env string, configDir string, zone string, config interface{}) error { // TODO: remove log dependency. stdlog.Printf("Loading config files=%v\n", files) + templateFuncs := sprig.FuncMap() + for _, f := range files { // This is tagged nosec because the file names being read are for config files that are not user supplied // #nosec @@ -97,7 +102,19 @@ func Load(env string, configDir string, zone string, config interface{}) error { if err != nil { return err } - err = yaml.Unmarshal(data, config) + + tpl, err := template.New("config").Funcs(templateFuncs).Parse(string(data)) + if err != nil { + return err + } + + var rendered bytes.Buffer + err = tpl.Execute(&rendered, nil) + if err != nil { + return err + } + + err = yaml.Unmarshal(rendered.Bytes(), config) if err != nil { return err } diff --git a/common/config/loader_test.go b/common/config/loader_test.go index 61dd4408fe4..56ba5fb446c 100644 --- a/common/config/loader_test.go +++ b/common/config/loader_test.go @@ -95,15 +95,15 @@ func (s *LoaderSuite) TestHierarchy() { item1 string item2 string }{ - {"", "", "hello_development_", "world_development_"}, - {"", "dca", "hello_development_", "world_development_"}, - {"", "pdx", "hello_development_", "world_development_"}, - {"development", "", "hello_development_", "world_development_"}, - {"development", "dca", "hello_development_", "world_development_"}, - {"development", "pdx", "hello_development_", "world_development_"}, - {"prod", "", "hello_prod_", "world_prod_"}, - {"prod", "dca", "hello_prod_dca", "world_prod_dca"}, - {"prod", "pdx", "hello_prod_", "world_prod_"}, + {"", "", "HELLO_DEVELOPMENT_", "world_development_"}, + {"", "dca", "HELLO_DEVELOPMENT_", "world_development_"}, + {"", "pdx", "HELLO_DEVELOPMENT_", "world_development_"}, + {"development", "", "HELLO_DEVELOPMENT_", "world_development_"}, + {"development", "dca", "HELLO_DEVELOPMENT_", "world_development_"}, + {"development", "pdx", "HELLO_DEVELOPMENT_", "world_development_"}, + {"prod", "", "HELLO_PROD_", "world_prod_"}, + {"prod", "dca", "HELLO_PROD_DCA", "world_prod_dca"}, + {"prod", "pdx", "HELLO_PROD_", "world_prod_"}, } for _, tc := range testCases { @@ -131,6 +131,6 @@ func buildConfig(env, zone string) string { item2 := concat("world", concat(env, zone)) return ` items: - item1: ` + item1 + ` + item1: {{ "` + item1 + `" | upper }} item2: ` + item2 } diff --git a/go.mod b/go.mod index 15c05c63fda..759d185ca64 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22.3 require ( cloud.google.com/go/storage v1.41.0 + github.com/Masterminds/sprig/v3 v3.2.3 github.com/aws/aws-sdk-go v1.53.15 github.com/blang/semver/v4 v4.0.0 github.com/cactus/go-statsd-client/v5 v5.1.0 @@ -79,6 +80,8 @@ require ( cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.8 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/apache/thrift v0.16.0 // indirect github.com/benbjohnson/clock v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -102,6 +105,8 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/huandu/xstrings v1.3.3 // indirect + github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect @@ -112,6 +117,8 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -121,7 +128,9 @@ require ( github.com/rivo/uniseg v0.2.0 // indirect github.com/robfig/cron v1.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.4.2 // indirect + github.com/spf13/cast v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/twmb/murmur3 v1.1.8 // indirect github.com/uber-common/bark v1.0.0 // indirect diff --git a/go.sum b/go.sum index 7ac8b7f4612..334c6b5e5a5 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +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/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= @@ -133,6 +139,7 @@ github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwg github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -150,8 +157,12 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= @@ -197,8 +208,12 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nexus-rpc/sdk-go v0.0.8-0.20240617225139-cd9d6c50e99d h1:OY7OVvmJgHji2GjQVaY1y4NHTZ5vvYr1GJaZTAjo/SQ= @@ -246,11 +261,15 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samuel/go-thrift v0.0.0-20190219015601-e8b6b52668fe/go.mod h1:Vrkh1pnjV9Bl8c3P9zH0/D4NlOHWP5d4/hF4YTULaec= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.0.2-0.20170726183946-abee6f9b0679/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -260,6 +279,7 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -351,6 +371,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= @@ -390,6 +411,7 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= @@ -423,6 +445,7 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -431,6 +454,7 @@ golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= @@ -438,6 +462,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -520,6 +545,7 @@ gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From aefdebdc6034b6412ba4d2a52446cd872a8e12ce Mon Sep 17 00:00:00 2001 From: Rob Holland Date: Mon, 8 Jul 2024 14:46:26 +0100 Subject: [PATCH 2/4] Adjust missed test. --- common/config/loader_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/loader_test.go b/common/config/loader_test.go index 56ba5fb446c..89c64765328 100644 --- a/common/config/loader_test.go +++ b/common/config/loader_test.go @@ -75,7 +75,7 @@ func (s *LoaderSuite) TestBaseYaml() { var cfg testConfig err = Load(env, dir, zone, &cfg) s.Nil(err) - s.Equal("hello__", cfg.Items.Item1) + s.Equal("HELLO__", cfg.Items.Item1) s.Equal("world__", cfg.Items.Item2) } } From 5293fc75970374f1bd07cf0854342d6197e923e0 Mon Sep 17 00:00:00 2001 From: Rob Holland Date: Mon, 12 Aug 2024 13:14:41 +0100 Subject: [PATCH 3/4] Add a port of the docker config template to sprig. Takes the opportunity to simplify the template a little and add some errors for common issues. --- config/docker.yaml | 350 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 config/docker.yaml diff --git a/config/docker.yaml b/config/docker.yaml new file mode 100644 index 00000000000..2cfbdac3373 --- /dev/null +++ b/config/docker.yaml @@ -0,0 +1,350 @@ +log: + stdout: true + level: {{ default "info" (env "LOG_LEVEL") }} + +persistence: + numHistoryShards: {{ default "4" (env "NUM_HISTORY_SHARDS") }} + + defaultStore: default + visibilityStore: visibility + + {{- if not (eq (env "DB") "cassandra" "mysql8" "postgres12" "postgres12_pgx") -}} + {{- fail "Invalid DB value. Supported values are cassandra, mysql8, postgres12, postgres12_pgx" -}} + {{- end }} + + datastores: + default: + {{- if eq $db "cassandra" }} + cassandra: + hosts: {{ env "CASSANDRA_SEEDS" }} + keyspace: {{ default "temporal" (env "KEYSPACE") | quote }} + user: {{ env "CASSANDRA_USER" | quote }} + password: {{ env "CASSANDRA_PASSWORD" | quote }} + {{- if env "CASSANDRA_ALLOWED_AUTHENTICATORS" }} + allowedAuthenticators: {{ range splitList "," (env "CASSANDRA_ALLOWED_AUTHENTICATORS") }} + - {{ trim . }} + {{- end }} + {{- end }} + port: {{ default "9042" (env "CASSANDRA_PORT") }} + maxConns: {{ default "20" (env "CASSANDRA_MAX_CONNS") }} + tls: + enabled: {{ default "false" (env "CASSANDRA_TLS_ENABLED") }} + caFile: {{ env "CASSANDRA_CA" }} + certFile: {{ env "CASSANDRA_CERT" }} + keyFile: {{ env "CASSANDRA_CERT_KEY" }} + caData: {{ env "CASSANDRA_CA_DATA" }} + certData: {{ env "CASSANDRA_CERT_DATA" }} + keyData: {{ env "CASSANDRA_CERT_KEY_DATA" }} + enableHostVerification: {{ default "false" (env "CASSANDRA_HOST_VERIFICATION") }} + serverName: {{ env "CASSANDRA_HOST_NAME" }} + {{- if env "CASSANDRA_ADDRESS_TRANSLATOR" }} + addressTranslator: + translator: {{ env "CASSANDRA_ADDRESS_TRANSLATOR" }} + {{- if env "CASSANDRA_ADDRESS_TRANSLATOR_OPTIONS" }} + options: + advertised-hostname: {{ env "CASSANDRA_ADDRESS_TRANSLATOR_OPTIONS" }} + {{- end }} + {{- end }} + {{- else if eq $db "mysql8" }} + sql: + pluginName: {{ $db }} + databaseName: {{ default "temporal" (env "DBNAME") | quote }} + connectAddr: {{ env "MYSQL_SEEDS" }}:{{ default "3306" (env "DB_PORT") }} + connectProtocol: "tcp" + user: {{ env "MYSQL_USER" | quote }} + password: {{ env "MYSQL_PWD" | quote }} + {{- if env "MYSQL_TX_ISOLATION_COMPAT" }} + connectAttributes: + tx_isolation: "'READ-COMMITTED'" + {{- end }} + maxConns: {{ default "20" (env "SQL_MAX_CONNS") }} + maxIdleConns: {{ default "20" (env "SQL_MAX_IDLE_CONNS") }} + maxConnLifetime: {{ default "1h" (env "SQL_MAX_CONN_TIME") }} + tls: + enabled: {{ default "false" (env "SQL_TLS_ENABLED") }} + caFile: {{ env "SQL_CA" }} + certFile: {{ env "SQL_CERT" }} + keyFile: {{ env "SQL_CERT_KEY" }} + enableHostVerification: {{ default "false" (env "SQL_HOST_VERIFICATION") }} + serverName: {{ env "SQL_HOST_NAME" }} + {{- else if eq $db "postgres12" "postgres12_pgx" }} + sql: + pluginName: {{ $db }} + databaseName: {{ default "temporal" (env "DBNAME") | quote }} + connectAddr: {{ env "POSTGRES_SEEDS" }}:{{ default "5432" (env "DB_PORT") }} + connectProtocol: "tcp" + user: {{ env "POSTGRES_USER" | quote }} + password: {{ env "POSTGRES_PWD" | quote }} + maxConns: {{ default "20" (env "SQL_MAX_CONNS") }} + maxIdleConns: {{ default "20" (env "SQL_MAX_IDLE_CONNS") }} + maxConnLifetime: {{ default "1h" (env "SQL_MAX_CONN_TIME") }} + tls: + enabled: {{ default "false" (env "SQL_TLS_ENABLED") }} + caFile: {{ env "SQL_CA" }} + certFile: {{ env "SQL_CERT" }} + keyFile: {{ env "SQL_CERT_KEY" }} + enableHostVerification: {{ default "false" (env "SQL_HOST_VERIFICATION") }} + serverName: {{ env "SQL_HOST_NAME" }} + {{- end }} + + visibility: + {{- if eq (env "ENABLE_ES") "true" }} + elasticsearch: + version: {{ env "ES_VERSION" }} + url: + scheme: {{ default "http" (env "ES_SCHEME") }} + host: {{ env "ES_SEEDS" }}:{{ default "9200" (env "ES_PORT") }} + username: {{ env "ES_USER" | quote }} + password: {{ env "ES_PWD" | quote }} + indices: + visibility: {{ default "temporal_visibility_v1_dev" (env "ES_VIS_INDEX") | quote }} + {{- with env "ES_SEC_VIS_INDEX" }} + secondary_visibility: {{ . | quote }} + {{- end }} + {{- else if eq $db "mysql8" }} + sql: + {{ $visibility_seeds := coalesce (env "VISIBILITY_MYSQL_SEEDS") (env "MYSQL_SEEDS") }} + {{ $visibility_port := coalesce (env "VISIBILITY_DB_PORT") (ENV "DB_PORT") "3306" }} + {{ $visibility_user_:= coalesce (env "VISIBILITY_MYSQL_USER") (env "MYSQL_USER") }} + {{ $visibility_pwd_:= coalesce (env "VISIBILITY_MYSQL_PWD") (env "MYSQL_PWD") }} + pluginName: {{ $db }} + databaseName: {{ default "temporal_visibility" (env "VISIBILITY_DBNAME") | quote }} + connectAddr: {{ $visibility_seeds }}:{{ $visibility_port }} + connectProtocol: "tcp" + user: {{ $visibility_user | quote }} + password: {{ $visibility_pwd | quote }} + {{- if env "MYSQL_TX_ISOLATION_COMPAT" }} + connectAttributes: + tx_isolation: "'READ-COMMITTED'" + {{- end }} + maxConns: {{ default "10" (env "SQL_VIS_MAX_CONNS") }} + maxIdleConns: {{ default "10" (env "SQL_VIS_MAX_IDLE_CONNS") }} + maxConnLifetime: {{ default "1h" (env "SQL_VIS_MAX_CONN_TIME") }} + tls: + enabled: {{ default "false" (env "SQL_TLS_ENABLED") }} + caFile: {{ env "SQL_CA" }} + certFile: {{ env "SQL_CERT" }} + keyFile: {{ env "SQL_CERT_KEY" }} + enableHostVerification: {{ default "false" (env "SQL_HOST_VERIFICATION") }} + serverName: {{ env "SQL_HOST_NAME" }} + {{- else if eq $db "postgres12" "postgres12_pgx" }} + sql: + {{ $visibility_seeds := coalesce (env "VISIBILITY_POSTGRES_SEEDS") (env "POSTGRES_SEEDS") }} + {{ $visibility_port := coalesce (env "VISIBILITY_DB_PORT") (env "POSTGRES_PORT") "5432" }} + {{ $visibility_user := coalesce (env "VISIBILITY_POSTGRES_USER") (env "POSTGRES_USER") }} + {{ $visibility_pwd := coalesce (env "VISIBILITY_POSTGRES_PWD") (env "POSTGRES_PWD") }} + pluginName: {{ $db }} + databaseName: {{ default "temporal_visibility" (env "VISIBILITY_DBNAME") | quote }} + connectAddr: {{ $visibility_seeds }}:{{ $visibility_port }} + connectProtocol: "tcp" + user: {{ $visibility_user | quote }} + password: {{ $visibility_pwd | quote }} + maxConns: {{ default "10" (env "SQL_VIS_MAX_CONNS") }} + maxIdleConns: {{ default "10" (env "SQL_VIS_MAX_IDLE_CONNS") }} + maxConnLifetime: {{ default "1h" (env "SQL_VIS_MAX_CONN_TIME") }} + tls: + enabled: {{ default "false" (env "SQL_TLS_ENABLED") }} + caFile: {{ env "SQL_CA" }} + certFile: {{ env "SQL_CERT" }} + keyFile: {{ env "SQL_CERT_KEY" }} + enableHostVerification: {{ default "false" (env "SQL_HOST_VERIFICATION") }} + serverName: {{ env "SQL_HOST_NAME" }} + {{- else -}} + {{- fail "No visibility configured. Cassandra is no longer supported for visibility." -}} + {{- end }} + +global: + membership: + maxJoinDuration: 30s + broadcastAddress: "{{ env "TEMPORAL_BROADCAST_ADDRESS" }}" + pprof: + port: {{ default "0" (env "PPROF_PORT") }} + tls: + refreshInterval: {{ default "0s" (env "TEMPORAL_TLS_REFRESH_INTERVAL") }} + expirationChecks: + warningWindow: {{ default "0s" (env "TEMPORAL_TLS_EXPIRATION_CHECKS_WARNING_WINDOW") }} + errorWindow: {{ default "0s" (env "TEMPORAL_TLS_EXPIRATION_CHECKS_ERROR_WINDOW") }} + checkInterval: {{ default "0s" (env "TEMPORAL_TLS_EXPIRATION_CHECKS_CHECK_INTERVAL") }} + internode: + # This server section configures the TLS certificate that internal temporal + # cluster nodes (history, matching, and internal-frontend) present to other + # clients within the Temporal Cluster. + server: + requireClientAuth: {{ default "false" (env "TEMPORAL_TLS_REQUIRE_CLIENT_AUTH") }} + + certFile: {{ env "TEMPORAL_TLS_SERVER_CERT" }} + keyFile: {{ env "TEMPORAL_TLS_SERVER_KEY" }} + {{- with "TEMPORAL_TLS_SERVER_CA_CERT" }} + clientCaFiles: + - {{ . }} + {{- end }} + + certData: {{ env "TEMPORAL_TLS_SERVER_CERT_DATA" }} + keyData: {{ env "TEMPORAL_TLS_SERVER_KEY_DATA" }} + {{- with env "TEMPORAL_TLS_SERVER_CA_CERT_DATA" }} + clientCaData: + - {{ . }} + {{- end }} + + # This client section is used to configure the TLS clients within + # the Temporal Cluster that connect to an Internode (history, matching, or + # internal-frontend) + client: + serverName: {{ env "TEMPORAL_TLS_INTERNODE_SERVER_NAME" }} + disableHostVerification: {{ default "false" (env "TEMPORAL_TLS_INTERNODE_DISABLE_HOST_VERIFICATION") }} + {{- with env "TEMPORAL_TLS_SERVER_CA_CERT" }} + rootCaFiles: + - {{ . }} + {{- end }} + {{- with env "TEMPORAL_TLS_SERVER_CA_CERT_DATA" }} + rootCaData: + - {{ . }} + {{- end }} + frontend: + # This server section configures the TLS certificate that the Frontend + # server presents to external clients. + server: + requireClientAuth: {{ default "false" (env "TEMPORAL_TLS_REQUIRE_CLIENT_AUTH") }} + certFile: {{ env "TEMPORAL_TLS_FRONTEND_CERT" }} + keyFile: {{ env "TEMPORAL_TLS_FRONTEND_KEY" }} + {{- if env "TEMPORAL_TLS_CLIENT1_CA_CERT" }} + clientCaFiles: + - {{ env "TEMPORAL_TLS_CLIENT1_CA_CERT" }} + - {{ env "TEMPORAL_TLS_CLIENT2_CA_CERT" }} + {{- end }} + + certData: {{ env "TEMPORAL_TLS_FRONTEND_CERT_DATA" }} + keyData: {{ env "TEMPORAL_TLS_FRONTEND_KEY_DATA" }} + {{- if env "TEMPORAL_TLS_CLIENT1_CA_CERT_DATA" }} + clientCaData: + - {{ env "TEMPORAL_TLS_CLIENT1_CA_CERT_DATA" }} + - {{ env "TEMPORAL_TLS_CLIENT2_CA_CERT_DATA" }} + {{- end }} + + # This client section is used to configure the TLS clients within + # the Temporal Cluster (specifically the Worker role) that connect to the Frontend service + client: + serverName: {{ env "TEMPORAL_TLS_FRONTEND_SERVER_NAME" }} + disableHostVerification: {{ default "false" (env "TEMPORAL_TLS_FRONTEND_DISABLE_HOST_VERIFICATION") }} + {{- with env "TEMPORAL_TLS_SERVER_CA_CERT" }} + rootCaFiles: + - {{ . }} + {{- end }} + {{- with env "TEMPORAL_TLS_SERVER_CA_CERT_DATA" }} + rootCaData: + - {{ . }} + {{- end }} + {{- with env "STATSD_ENDPOINT" }} + metrics: + statsd: + hostPort: {{ . }} + prefix: "temporal" + {{- with env "PROMETHEUS_ENDPOINT" }} + metrics: + prometheus: + timerType: {{ default "histogram" (env "PROMETHEUS_TIMER_TYPE") }} + listenAddress: {{ . }} + {{- end }} + authorization: + jwtKeyProvider: + keySourceURIs: + {{- with env "TEMPORAL_JWT_KEY_SOURCE1" }} + - {{ . }} + {{- end }} + {{- with env "TEMPORAL_JWT_KEY_SOURCE2" }} + - {{ . }} + {{- end }} + refreshInterval: {{ default "1m" (env "TEMPORAL_JWT_KEY_REFRESH") }} + permissionsClaimName: {{ default "permissions" (env "TEMPORAL_JWT_PERMISSIONS_CLAIM") }} + authorizer: {{ env "TEMPORAL_AUTH_AUTHORIZER" }} + claimMapper: {{ env "TEMPORAL_AUTH_CLAIM_MAPPER" }} + +{{- $temporalGrpcPort := default "7233" (env "FRONTEND_GRPC_PORT") }} +{{- $temporalHTTPPort := default "7243" (env "FRONTEND_HTTP_PORT") }} +services: + frontend: + rpc: + grpcPort: {{ $temporalGrpcPort }} + membershipPort: {{ default "6933" (env "FRONTEND_MEMBERSHIP_PORT") }} + bindOnIP: {{ default "127.0.0.1" (env "BIND_ON_IP") }} + httpPort: {{ $temporalHTTPPort }} + + {{- if env "USE_INTERNAL_FRONTEND" }} + internal-frontend: + rpc: + grpcPort: {{ default "7236" (env "INTERNAL_FRONTEND_GRPC_PORT") }} + membershipPort: {{ default "6936" (env "INTERNAL_FRONTEND_MEMBERSHIP_PORT") }} + bindOnIP: {{ default "127.0.0.1" (env "BIND_ON_IP") }} + {{- end }} + + matching: + rpc: + grpcPort: {{ default "7235" (env "MATCHING_GRPC_PORT") }} + membershipPort: {{ default "6935" (env "MATCHING_MEMBERSHIP_PORT") }} + bindOnIP: {{ default "127.0.0.1" (env "BIND_ON_IP") }} + + history: + rpc: + grpcPort: {{ default "7234" (env "HISTORY_GRPC_PORT") }} + membershipPort: {{ default "6934" (env "HISTORY_MEMBERSHIP_PORT") }} + bindOnIP: {{ default "127.0.0.1" (env "BIND_ON_IP") }} + + worker: + rpc: + grpcPort: {{ default "7239" (env "WORKER_GRPC_PORT") }} + membershipPort: {{ default "6939" (env "WORKER_MEMBERSHIP_PORT") }} + bindOnIP: {{ default "127.0.0.1" (env "BIND_ON_IP") }} + +clusterMetadata: + enableGlobalNamespace: false + failoverVersionIncrement: 10 + masterClusterName: "active" + currentClusterName: "active" + clusterInformation: + active: + enabled: true + initialFailoverVersion: 1 + rpcName: "frontend" + rpcAddress: "127.0.0.1:{{ $temporalGrpcPort }}" + httpAddress: "127.0.0.1:{{ $temporalHTTPPort }}" + +dcRedirectionPolicy: + policy: "noop" + +archival: + history: + state: "enabled" + enableRead: true + provider: + filestore: + fileMode: "0666" + dirMode: "0766" + visibility: + state: "enabled" + enableRead: true + provider: + filestore: + fileMode: "0666" + dirMode: "0766" + +namespaceDefaults: + archival: + history: + state: "disabled" + URI: "file:///tmp/temporal_archival/development" + visibility: + state: "disabled" + URI: "file:///tmp/temporal_vis_archival/development" + +{{- if or (env "USE_INTERNAL_FRONTEND") (and (not (env "TEMPORAL_AUTH_AUTHORIZER")) (not (env "TEMPORAL_AUTH_CLAIM_MAPPER"))) }} +{{/* publicClient is not needed with internal frontend, or if not using authorizer + claim mapper */}} +{{- else }} +{{ $publicIp := default "127.0.0.1" (env "BIND_ON_IP") -}} +{{- $defaultPublicHostPost := print $publicIp ":" $temporalGrpcPort -}} +publicClient: + hostPort: "{{ default $defaultPublicHostPost (env "PUBLIC_FRONTEND_ADDRESS") }}" +{{- end }} + +dynamicConfigClient: + filepath: "{{ default "/etc/temporal/config/dynamicconfig/docker.yaml" (env "DYNAMIC_CONFIG_FILE_PATH") }}" + pollInterval: "60s" From 1efd952e8c8cea44c863c54f4c99ecf882923a4d Mon Sep 17 00:00:00 2001 From: Rob Holland Date: Tue, 13 Aug 2024 17:31:53 +0100 Subject: [PATCH 4/4] Improve error messages. --- common/config/loader.go | 4 ++-- config/docker.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/config/loader.go b/common/config/loader.go index a74a42bf772..176cd244321 100644 --- a/common/config/loader.go +++ b/common/config/loader.go @@ -105,13 +105,13 @@ func Load(env string, configDir string, zone string, config interface{}) error { tpl, err := template.New("config").Funcs(templateFuncs).Parse(string(data)) if err != nil { - return err + return fmt.Errorf("template parsing error: %w", err) } var rendered bytes.Buffer err = tpl.Execute(&rendered, nil) if err != nil { - return err + return fmt.Errorf("template execution error: %w", err) } err = yaml.Unmarshal(rendered.Bytes(), config) diff --git a/config/docker.yaml b/config/docker.yaml index 2cfbdac3373..e87fec876ae 100644 --- a/config/docker.yaml +++ b/config/docker.yaml @@ -4,7 +4,7 @@ log: persistence: numHistoryShards: {{ default "4" (env "NUM_HISTORY_SHARDS") }} - + defaultStore: default visibilityStore: visibility