4
4
"bufio"
5
5
"bytes"
6
6
"context"
7
+ "encoding/json"
7
8
"errors"
8
9
"fmt"
9
10
"io"
@@ -16,6 +17,12 @@ import (
16
17
"github.com/spf13/afero"
17
18
)
18
19
20
+ // secretSourceConfig represents the configuration for the secrets store
21
+ type secretSourceConfig struct {
22
+ URL string `json:"url"`
23
+ Token string `json:"token"`
24
+ }
25
+
19
26
type Local struct {
20
27
k6path string
21
28
logger * zerolog.Logger
@@ -68,7 +75,18 @@ func (r Local) Run(ctx context.Context, script Script) (*RunResponse, error) {
68
75
return nil , fmt .Errorf ("cannot write temporary script file: %w" , err )
69
76
}
70
77
71
- k6Path , err := exec .LookPath (r .k6path )
78
+ executable := r .k6path
79
+ // TODO(d0ugal): This is a short-term hack to use a different k6 binary when
80
+ // secrets are configured. This should be removed when the default binary has been updated
81
+ if script .SecretStore .IsConfigured () {
82
+ executable = r .k6path + "-gsm"
83
+ logger .Info ().
84
+ Str ("k6_path" , r .k6path ).
85
+ Str ("k6_gsm_path" , executable ).
86
+ Msg ("Using k6-gsm binary for secrets" )
87
+ }
88
+
89
+ k6Path , err := exec .LookPath (executable )
72
90
if err != nil {
73
91
return nil , fmt .Errorf ("cannot find k6 executable: %w" , err )
74
92
}
@@ -77,37 +95,21 @@ func (r Local) Run(ctx context.Context, script Script) (*RunResponse, error) {
77
95
ctx , cancel = context .WithTimeout (ctx , checkTimeout )
78
96
defer cancel ()
79
97
80
- args := []string {
81
- "run" ,
82
- "--out" , "sm=" + metricsFn ,
83
- "--log-format" , "logfmt" ,
84
- "--log-output" , "file=" + logsFn ,
85
- "--max-redirects" , "10" ,
86
- "--batch" , "10" ,
87
- "--batch-per-host" , "4" ,
88
- "--no-connection-reuse" ,
89
- "--blacklist-ip" , r .blacklistedIP ,
90
- "--block-hostnames" , "*.cluster.local" , // TODO(mem): make this configurable
91
- "--summary-time-unit" , "s" ,
92
- // "--discard-response-bodies", // TODO(mem): make this configurable
93
- "--dns" , "ttl=30s,select=random,policy=preferIPv4" , // TODO(mem): this needs fixing, preferIPv4 is probably not what we want
94
- "--address" , "" , // Disable REST API server
95
- "--no-thresholds" ,
96
- "--no-usage-report" ,
97
- "--no-color" ,
98
- "--no-summary" ,
99
- "--verbose" ,
98
+ var configFile string
99
+ if script .SecretStore .IsConfigured () {
100
+ var cleanup func ()
101
+ configFile , cleanup , err = createSecretConfigFile (script .SecretStore .Url , script .SecretStore .Token )
102
+ if err != nil {
103
+ return nil , fmt .Errorf ("cannot create secret config file: %w" , err )
104
+ }
105
+ defer cleanup ()
100
106
}
101
107
102
- if script .CheckInfo .Type != synthetic_monitoring .CheckTypeBrowser .String () {
103
- args = append (args ,
104
- "--vus" , "1" ,
105
- "--iterations" , "1" ,
106
- )
108
+ args , err := r .buildK6Args (script , metricsFn , logsFn , scriptFn , configFile )
109
+ if err != nil {
110
+ return nil , fmt .Errorf ("building k6 arguments: %w" , err )
107
111
}
108
112
109
- args = append (args , scriptFn )
110
-
111
113
cmd := exec .CommandContext (
112
114
ctx ,
113
115
k6Path ,
@@ -187,6 +189,46 @@ func (r Local) Run(ctx context.Context, script Script) (*RunResponse, error) {
187
189
return & RunResponse {Metrics : metrics .Bytes (), Logs : logs .Bytes ()}, errors .Join (err , errorFromLogs (logs .Bytes ()))
188
190
}
189
191
192
+ func (r Local ) buildK6Args (script Script , metricsFn , logsFn , scriptFn , configFile string ) ([]string , error ) {
193
+ args := []string {
194
+ "run" ,
195
+ "--out" , "sm=" + metricsFn ,
196
+ "--log-format" , "logfmt" ,
197
+ "--log-output" , "file=" + logsFn ,
198
+ "--max-redirects" , "10" ,
199
+ "--batch" , "10" ,
200
+ "--batch-per-host" , "4" ,
201
+ "--no-connection-reuse" ,
202
+ "--blacklist-ip" , r .blacklistedIP ,
203
+ "--block-hostnames" , "*.cluster.local" , // TODO(mem): make this configurable
204
+ "--summary-time-unit" , "s" ,
205
+ // "--discard-response-bodies", // TODO(mem): make this configurable
206
+ "--dns" , "ttl=30s,select=random,policy=preferIPv4" , // TODO(mem): this needs fixing, preferIPv4 is probably not what we want
207
+ "--address" , "" , // Disable REST API server
208
+ "--no-thresholds" ,
209
+ "--no-usage-report" ,
210
+ "--no-color" ,
211
+ "--no-summary" ,
212
+ "--verbose" ,
213
+ }
214
+
215
+ // Add secretStore configuration if available
216
+ if script .SecretStore .IsConfigured () {
217
+ args = append (args , "--secret-source" , "grafanasecrets=config=" + configFile )
218
+ }
219
+
220
+ if script .CheckInfo .Type != synthetic_monitoring .CheckTypeBrowser .String () {
221
+ args = append (args ,
222
+ "--vus" , "1" ,
223
+ "--iterations" , "1" ,
224
+ )
225
+ }
226
+
227
+ args = append (args , scriptFn )
228
+
229
+ return args , nil
230
+ }
231
+
190
232
func mktemp (fs afero.Fs , dir , pattern string ) (string , error ) {
191
233
f , err := afero .TempFile (fs , dir , pattern )
192
234
if err != nil {
@@ -262,3 +304,39 @@ func readFileLimit(f afero.Fs, name string, limit int64) (*bytes.Buffer, bool, e
262
304
263
305
return buf , true , nil
264
306
}
307
+
308
+ // createSecretConfigFile creates a JSON config file with the given secret store URL and token
309
+ func createSecretConfigFile (url , token string ) (filename string , cleanup func (), err error ) {
310
+ tmpFile , err := os .CreateTemp ("" , "k6-secrets-*.json" )
311
+ if err != nil {
312
+ return "" , nil , fmt .Errorf ("creating temp file: %w" , err )
313
+ }
314
+
315
+ if err := os .Chmod (tmpFile .Name (), 0600 ); err != nil {
316
+ os .Remove (tmpFile .Name ())
317
+ return "" , nil , fmt .Errorf ("setting file permissions: %w" , err )
318
+ }
319
+
320
+ config := secretSourceConfig {
321
+ URL : url ,
322
+ Token : token ,
323
+ }
324
+
325
+ configData , err := json .Marshal (config )
326
+ if err != nil {
327
+ os .Remove (tmpFile .Name ())
328
+ return "" , nil , fmt .Errorf ("marshaling config to JSON: %w" , err )
329
+ }
330
+
331
+ if _ , err := tmpFile .Write (configData ); err != nil {
332
+ os .Remove (tmpFile .Name ())
333
+ return "" , nil , fmt .Errorf ("writing config file: %w" , err )
334
+ }
335
+
336
+ if err := tmpFile .Close (); err != nil {
337
+ os .Remove (tmpFile .Name ())
338
+ return "" , nil , fmt .Errorf ("closing config file: %w" , err )
339
+ }
340
+
341
+ return tmpFile .Name (), func () { os .Remove (tmpFile .Name ()) }, nil
342
+ }
0 commit comments