@@ -4,12 +4,30 @@ import (
44 "context"
55 "encoding/json"
66 "fmt"
7- "github.com/BurntSushi/toml"
87 "io"
98 "reflect"
109 "strings"
10+ "sync"
11+ "sync/atomic"
12+
13+ "github.com/BurntSushi/toml"
14+ "golang.org/x/sync/errgroup"
1115)
1216
17+ var builderWorkers atomic.Int32
18+
19+ func init () {
20+ builderWorkers .Store (10 )
21+ }
22+
23+ // SetBuilderWorkers set the amount of concurrent request to the secret manager
24+ func SetBuilderWorkers (n int32 ) {
25+ if n < 1 {
26+ n = 1
27+ }
28+ builderWorkers .Store (n )
29+ }
30+
1331type Builder struct {
1432 sources []* StaticSource
1533 managers []SecretManager
@@ -59,12 +77,20 @@ func buildFromSources(config any, sources []*StaticSource) error {
5977 }
6078
6179 if err != nil {
62- return fmt .Errorf ("failed to process source: %s, %w" , source .name , err )
80+ return fmt .Errorf (
81+ "failed to process source: %s, %w" ,
82+ source .name ,
83+ err ,
84+ )
6385 }
6486
6587 err = source .reader .Close ()
6688 if err != nil {
67- return fmt .Errorf ("failed to close source: %s, %s" , source .name , err )
89+ return fmt .Errorf (
90+ "failed to close source: %s, %s" ,
91+ source .name ,
92+ err ,
93+ )
6894 }
6995 }
7096
@@ -80,26 +106,66 @@ func parseJSON(config any, r io.Reader) error {
80106 return json .NewDecoder (r ).Decode (config )
81107}
82108
83- func resolveSecrets (ctx context.Context , config any , managers []SecretManager ) error {
109+ type replacement struct {
110+ old string
111+ new string
112+ }
113+
114+ func resolveSecrets (
115+ ctx context.Context ,
116+ config any ,
117+ managers []SecretManager ,
118+ ) error {
119+ g , ctx := errgroup .WithContext (ctx )
120+ g .SetLimit (int (builderWorkers .Load ()))
121+
122+ var mu sync.Mutex
123+
84124 strConfig , err := configToJSON (config )
85125 if err != nil {
86126 return err
87127 }
88128
89129 subs := findSubstitutions (strConfig )
130+ replacements := make ([]replacement , 0 , len (subs ))
90131 for _ , sub := range subs {
132+ sub := sub
91133 manager , err := getManagerForPrefix (sub .managerPrefix , managers )
92134 if err != nil {
93135 return err
94136 }
95137
96- secret , err := manager .Secret (ctx , sub .managerKey )
97- if err != nil {
98- return err
99- }
138+ g .Go (func () error {
139+ select {
140+ case <- ctx .Done ():
141+ return nil
142+ default :
143+ }
144+
145+ secret , err := manager .Secret (ctx , sub .managerKey )
146+ if err != nil {
147+ return err
148+ }
149+
150+ escapedSecret := escape (secret )
151+
152+ mu .Lock ()
153+ replacements = append (
154+ replacements ,
155+ replacement {old : sub .value , new : escapedSecret },
156+ )
157+ mu .Unlock ()
158+ return nil
159+ })
160+ }
161+
162+ if err := g .Wait (); err != nil {
163+ return err
164+ }
100165
101- escapedSecret := escape (secret )
102- strConfig = strings .Replace (strConfig , sub .value , escapedSecret , 1 )
166+ // actually do the replacement
167+ for _ , r := range replacements {
168+ strConfig = strings .Replace (strConfig , r .old , r .new , 1 )
103169 }
104170
105171 return parseJSON (config , strings .NewReader (strConfig ))
@@ -151,7 +217,10 @@ func findSubstitutions(str string) []substitutions {
151217 return out
152218}
153219
154- func getManagerForPrefix (prefix string , managers []SecretManager ) (SecretManager , error ) {
220+ func getManagerForPrefix (
221+ prefix string ,
222+ managers []SecretManager ,
223+ ) (SecretManager , error ) {
155224 for _ , manager := range managers {
156225 if manager .Prefix () == prefix {
157226 return manager , nil
0 commit comments