Skip to content

Commit a602fc6

Browse files
cli: support dev Envoy version natively via func-e v1.6.0 (#444)
Testing unreleased Envoy features with BOE previously meant using Docker and the distroless-dev image tag, which only works on Linux and bypasses func-e entirely. func-e v1.6.0 added native dev builds backed by the same daily archive-envoy pipeline that publishes released versions. The dev key in envoy-versions.json carries a commitSha that traces back to the exact envoyproxy/envoy Docker image it was extracted from. `--envoy-versions-url` (or `ENVOY_VERSIONS_URL`) passes a custom versions JSON URL through to func-e. `dev` and `dev-latest` are accepted as Envoy version strings and bypass the semver compatibility check against extension manifests. ```console $ boe run --envoy-version dev-latest --local extensions/example-lua --envoy-versions-url https://archive.tetratelabs.io/envoy/envoy-versions_debug.json ``` Signed-off-by: Adrian Cole <adrian@tetrate.io>
1 parent 87d9f38 commit a602fc6

16 files changed

Lines changed: 103 additions & 34 deletions

File tree

cli/cmd/genconfig.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,13 @@ func copyFile(srcPath, dstPath string, logger *slog.Logger) error {
247247
// printExportSummary prints information about how to use the exported configuration.
248248
func printExportSummary(stdout io.Writer, outputPath string, files []string, listenPort, adminPort uint32, envoyVersion string) {
249249
adminPortStr := strconv.FormatUint(uint64(adminPort), 10)
250-
if envoyVersion == "" {
251-
envoyVersion = "dev"
252-
} else if !strings.HasPrefix(envoyVersion, "v") {
253-
envoyVersion = "v" + envoyVersion
250+
funcEEnvoyVersion := envoyVersion
251+
if funcEEnvoyVersion == "" {
252+
funcEEnvoyVersion = "dev"
253+
}
254+
dockerEnvoyTag := funcEEnvoyVersion
255+
if dockerEnvoyTag != "dev" && !strings.HasPrefix(dockerEnvoyTag, "v") {
256+
dockerEnvoyTag = "v" + dockerEnvoyTag
254257
}
255258

256259
_, _ = fmt.Fprintf(stdout, "\n%v✓ Config exported to:%v %s\n",
@@ -262,7 +265,7 @@ func printExportSummary(stdout io.Writer, outputPath string, files []string, lis
262265
%[1]s→ Run locally with with func-e:%[2]s (https://func-e.io/)
263266
cd %[3]s
264267
export GODEBUG=cgocheck=0
265-
func-e run -c envoy.yaml --log-level info --component-log-level dynamic_modules:debug
268+
ENVOY_VERSION=%[6]s func-e run -c envoy.yaml --log-level info --component-log-level dynamic_modules:debug
266269
267270
%[1]s→ Run locally in Docker:%[2]s (not supported in Darwin hosts yet)
268271
docker run --rm \
@@ -272,6 +275,6 @@ func printExportSummary(stdout io.Writer, outputPath string, files []string, lis
272275
-e GODEBUG=cgocheck=0 \
273276
-v /tmp/boe-export:/boe \
274277
-w /boe \
275-
envoyproxy/envoy:%[6]s -c /boe/envoy.yaml --log-level info --component-log-level dynamic_modules:debug
276-
`, internal.ANSIBold, internal.ANSIReset, outputPath, listenPort, adminPortStr, envoyVersion)
278+
envoyproxy/envoy:%[7]s -c /boe/envoy.yaml --log-level info --component-log-level dynamic_modules:debug
279+
`, internal.ANSIBold, internal.ANSIReset, outputPath, listenPort, adminPortStr, funcEEnvoyVersion, dockerEnvoyTag)
277280
}

cli/cmd/genconfig_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ func TestPrintExportSummary(t *testing.T) {
371371
%[1]s→ Run locally with with func-e:%[2]s (https://func-e.io/)
372372
cd /tmp/boe-export
373373
export GODEBUG=cgocheck=0
374-
func-e run -c envoy.yaml --log-level info --component-log-level dynamic_modules:debug
374+
ENVOY_VERSION=%[3]s func-e run -c envoy.yaml --log-level info --component-log-level dynamic_modules:debug
375375
376376
%[1]s→ Run locally in Docker:%[2]s (not supported in Darwin hosts yet)
377377
docker run --rm \
@@ -381,18 +381,18 @@ func TestPrintExportSummary(t *testing.T) {
381381
-e GODEBUG=cgocheck=0 \
382382
-v /tmp/boe-export:/boe \
383383
-w /boe \
384-
envoyproxy/envoy:%[3]s -c /boe/envoy.yaml --log-level info --component-log-level dynamic_modules:debug
384+
envoyproxy/envoy:%[4]s -c /boe/envoy.yaml --log-level info --component-log-level dynamic_modules:debug
385385
`
386386

387387
t.Run("with Envoy version", func(t *testing.T) {
388388
var buf bytes.Buffer
389389
printExportSummary(&buf, "/tmp/boe-export", []string{"envoy.yaml", "libcomposer.so"}, 10000, 9901, "1.38.0")
390-
require.Equal(t, fmt.Sprintf(wantTemplate, internal.ANSIBold, internal.ANSIReset, "v1.38.0"), buf.String())
390+
require.Equal(t, fmt.Sprintf(wantTemplate, internal.ANSIBold, internal.ANSIReset, "1.38.0", "v1.38.0"), buf.String())
391391
})
392392

393-
t.Run("without Envoy version defaults to 'dev' for Docker", func(t *testing.T) {
393+
t.Run("without Envoy version defaults to 'dev'", func(t *testing.T) {
394394
var buf bytes.Buffer
395395
printExportSummary(&buf, "/tmp/boe-export", []string{"envoy.yaml", "libcomposer.so"}, 10000, 9901, "")
396-
require.Equal(t, fmt.Sprintf(wantTemplate, internal.ANSIBold, internal.ANSIReset, "dev"), buf.String())
396+
require.Equal(t, fmt.Sprintf(wantTemplate, internal.ANSIBold, internal.ANSIReset, "dev", "dev"), buf.String())
397397
})
398398
}

cli/cmd/run.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,16 @@ const defaultLogLevel = "error"
3131

3232
// Run is a command to run Envoy with extensions.
3333
type Run struct {
34-
EnvoyVersion string `help:"Envoy version to use (e.g., 1.31.0)" env:"ENVOY_VERSION"`
35-
EnvoyPath string `name:"envoy-path" help:"Path to a custom Envoy binary. Skips Envoy download and version selection." env:"ENVOY_PATH" type:"existingfile"`
36-
LogLevel string `help:"Envoy component log level." default:"all:error" env:"ENVOY_LOG_LEVEL"`
37-
RunID string `name:"run-id" env:"BOE_RUN_ID" help:"Run identifier for this invocation. Overrides the default timestamp-based ID."`
38-
ListenPort uint32 `help:"Port for Envoy listener to accept incoming traffic." default:"10000"`
39-
AdminPort uint32 `name:"admin-port" help:"Port for Envoy admin interface." default:"9901" env:"BOE_ADMIN_PORT"`
40-
Extensions []string `name:"extension" help:"Extensions to enable (in the format: \"name\" or \"name:version\")."`
41-
Local []string `name:"local" sep:"none" help:"Path to a directory containing a local Extension to enable." type:"existingdir"`
42-
Dev bool `help:"Whether to allow downloading dev versions of extensions (with -dev suffix). By default, only stable versions are allowed." default:"false"`
34+
EnvoyVersion string `help:"Envoy version to use (e.g., 1.31.0, dev, dev-latest)" env:"ENVOY_VERSION"`
35+
EnvoyVersionsURL string `name:"envoy-versions-url" help:"URL of the Envoy versions JSON. Override to use debug builds (see archive-envoy)." env:"ENVOY_VERSIONS_URL" hidden:""`
36+
EnvoyPath string `name:"envoy-path" help:"Path to a custom Envoy binary. Skips Envoy download and version selection." env:"ENVOY_PATH" type:"existingfile"`
37+
LogLevel string `help:"Envoy component log level." default:"all:error" env:"ENVOY_LOG_LEVEL"`
38+
RunID string `name:"run-id" env:"BOE_RUN_ID" help:"Run identifier for this invocation. Overrides the default timestamp-based ID."`
39+
ListenPort uint32 `help:"Port for Envoy listener to accept incoming traffic." default:"10000"`
40+
AdminPort uint32 `name:"admin-port" help:"Port for Envoy admin interface." default:"9901" env:"BOE_ADMIN_PORT"`
41+
Extensions []string `name:"extension" help:"Extensions to enable (in the format: \"name\" or \"name:version\")."`
42+
Local []string `name:"local" sep:"none" help:"Path to a directory containing a local Extension to enable." type:"existingdir"`
43+
Dev bool `help:"Whether to allow downloading dev versions of extensions (with -dev suffix). By default, only stable versions are allowed." default:"false"`
4344
// sep:"none" disables Kong's default comma-separated splitting for []string flags.
4445
// JSON config values contain commas (e.g. {"a":"1","b":"2"}) which would otherwise
4546
// be split into separate invalid fragments, causing protobuf unmarshal failures.
@@ -190,6 +191,7 @@ func (r *Run) Run(ctx context.Context, dirs *xdg.Directories, logger *slog.Logge
190191
runner := &envoy.RunnerFuncE{
191192
Logger: logger,
192193
EnvoyVersion: r.EnvoyVersion,
194+
EnvoyVersionsURL: r.EnvoyVersionsURL,
193195
EnvoyPath: r.EnvoyPath,
194196
DefaultLogLevel: r.defaultLogLevel,
195197
ComponentLogLevel: r.componentLogLevel,

cli/cmd/run_test.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ Run Envoy with extensions
5050
Flags:
5151
-h, --help Show context-sensitive help.
5252
53-
--envoy-version=STRING Envoy version to use (e.g., 1.31.0)
54-
($ENVOY_VERSION)
53+
--envoy-version=STRING Envoy version to use (e.g., 1.31.0, dev,
54+
dev-latest) ($ENVOY_VERSION)
5555
--envoy-path=STRING Path to a custom Envoy binary. Skips Envoy
5656
download and version selection ($ENVOY_PATH).
5757
--log-level="all:error" Envoy component log level ($ENVOY_LOG_LEVEL).
@@ -596,6 +596,20 @@ func TestValidateEnvoyCompat(t *testing.T) {
596596
`incompatible Envoy version 1.31.0: extension ext-3 (2.0.0) requires Envoy ">= 1.31.1 && <= 1.32.0"`,
597597
},
598598
},
599+
{
600+
name: "dev aliases are compatible with constrained extensions",
601+
envoyVersion: "dev",
602+
extensions: []*extensions.Manifest{
603+
{Name: "ext-1", Version: "1.0.0", MinEnvoyVersion: "1.38.0", MaxEnvoyVersion: "1.39.0"},
604+
},
605+
},
606+
{
607+
name: "dev-latest alias is compatible with constrained extensions",
608+
envoyVersion: "dev-latest",
609+
extensions: []*extensions.Manifest{
610+
{Name: "ext-1", Version: "1.0.0", MinEnvoyVersion: "1.38.0", MaxEnvoyVersion: "1.39.0"},
611+
},
612+
},
599613
}
600614

601615
for _, tt := range tests {

cli/e2e/run_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ func TestLuaRemoteExecution(t *testing.T) {
6666
require.NoError(t, internaltesting.CheckGet(ctx, url, checkHeader))
6767
}
6868

69+
func TestDevEnvoyVersion(t *testing.T) {
70+
ports := internaltesting.FreePorts(t, 2)
71+
proxyPort, adminPort := ports[0], ports[1]
72+
internaltesting.RunEnvoy(t, cliBin, proxyPort, adminPort, "--envoy-version", "dev-latest")
73+
74+
ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second)
75+
t.Cleanup(cancel)
76+
77+
require.NoError(t, internaltesting.CheckGet(ctx, fmt.Sprintf("http://localhost:%d/status/200", proxyPort), internaltesting.EqualStatus(200)))
78+
}
79+
6980
func TestLuaLocalExtension(t *testing.T) {
7081
ports := internaltesting.FreePorts(t, 2)
7182
proxyPort := ports[0]

cli/internal/envoy/runner.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ type RunnerFuncE struct {
4040
Logger *slog.Logger
4141
// EnvoyVersion specifies the Envoy version to run. If empty, the default version is used.
4242
EnvoyVersion string
43+
// EnvoyVersionsURL overrides the Envoy versions JSON URL (e.g. for debug builds).
44+
EnvoyVersionsURL string
4345
// EnvoyPath specifies a custom Envoy binary path. If set, download and version selection are skipped.
4446
EnvoyPath string
4547
// DefaultLogLevel specifies the base Envoy log level.
@@ -176,6 +178,9 @@ Press Ctrl+C to stop
176178
if r.EnvoyVersion != "" {
177179
opts = append(opts, api.EnvoyVersion(r.EnvoyVersion))
178180
}
181+
if r.EnvoyVersionsURL != "" {
182+
opts = append(opts, api.EnvoyVersionsURL(r.EnvoyVersionsURL))
183+
}
179184
if r.EnvoyPath != "" {
180185
opts = append(opts, api.EnvoyPath(r.EnvoyPath))
181186
}

cli/internal/extensions/manifest.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ type (
132132

133133
// SupportsEnvoyVersion checks if the extension supports the given Envoy version.
134134
func (m *Manifest) SupportsEnvoyVersion(version string) bool {
135+
if version == "dev" || version == "dev-latest" {
136+
return true
137+
}
135138
envoySemver := "v" + version
136139
if m.MinEnvoyVersion != "" && semver.Compare(envoySemver, "v"+m.MinEnvoyVersion) < 0 {
137140
return false

cli/internal/extensions/manifest_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,37 @@ func TestSupportsEnvoyVersion(t *testing.T) {
250250
version: "1.30.2",
251251
want: true,
252252
},
253+
{
254+
name: "dev - no constraints",
255+
version: "dev",
256+
want: true,
257+
},
258+
{
259+
name: "dev - with min",
260+
minEnvoyVersion: "1.38.0",
261+
version: "dev",
262+
want: true,
263+
},
264+
{
265+
name: "dev - with max",
266+
maxEnvoyVersion: "1.39.0",
267+
version: "dev",
268+
want: true,
269+
},
270+
{
271+
name: "dev - with min and max",
272+
minEnvoyVersion: "1.38.0",
273+
maxEnvoyVersion: "1.39.0",
274+
version: "dev",
275+
want: true,
276+
},
277+
{
278+
name: "dev-latest - with min and max",
279+
minEnvoyVersion: "1.38.0",
280+
maxEnvoyVersion: "1.39.0",
281+
version: "dev-latest",
282+
want: true,
283+
},
253284
}
254285

255286
for _, tt := range tests {

cli/tools/gen-cli-docs/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ require (
2222
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
2323
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
2424
github.com/shirou/gopsutil/v4 v4.26.3 // indirect
25-
github.com/tetratelabs/func-e v1.5.0 // indirect
25+
github.com/tetratelabs/func-e v1.6.0 // indirect
2626
github.com/tklauser/go-sysconf v0.3.16 // indirect
2727
github.com/tklauser/numcpus v0.11.0 // indirect
2828
github.com/ulikunitz/lz v0.6.11 // indirect

cli/tools/gen-cli-docs/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
110110
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
111111
github.com/testcontainers/testcontainers-go v0.42.0 h1:He3IhTzTZOygSXLJPMX7n44XtK+qhjat1nI9cneBbUY=
112112
github.com/testcontainers/testcontainers-go v0.42.0/go.mod h1:vZjdY1YmUA1qEForxOIOazfsrdyORJAbhi0bp8plN30=
113-
github.com/tetratelabs/func-e v1.5.0 h1:usqnwqIlLereQdua/BYLwFNfnNX7qGOFUGPihp8KMo0=
114-
github.com/tetratelabs/func-e v1.5.0/go.mod h1:9d/4Wne/HSg8pM+6fNhUePCsbQLeDrajn+wwbiN5WS4=
113+
github.com/tetratelabs/func-e v1.6.0 h1:TlTVVCSX/I+SBg6NWtU8On7EjrGz2/kxHQUtOo5tl1U=
114+
github.com/tetratelabs/func-e v1.6.0/go.mod h1:9d/4Wne/HSg8pM+6fNhUePCsbQLeDrajn+wwbiN5WS4=
115115
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
116116
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
117117
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=

0 commit comments

Comments
 (0)