Skip to content

Commit 777421a

Browse files
nacxaabchoo
andauthored
cli: handle standalone Envoy startup failures (#1994)
**Description** In standalone mode, handle EG infrastructure errors and exit gracefully instead of hanging. **Related Issues/PRs (if applicable)** Related to: #1304 **Special notes for reviewers (if applicable)** N/A --------- Signed-off-by: Ignasi Barrera <nacx@apache.org> Co-authored-by: Aaron Choo <achoo30@bloomberg.net>
1 parent bc72971 commit 777421a

2 files changed

Lines changed: 77 additions & 1 deletion

File tree

cmd/aigw/run.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"strings"
2020
"time"
2121

22+
egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
2223
"github.com/envoyproxy/gateway/cmd/envoy-gateway/root"
2324
egextension "github.com/envoyproxy/gateway/proto/extension"
2425
"github.com/go-logr/logr"
@@ -206,8 +207,9 @@ func run(ctx context.Context, c *cmdRun, o *runOpts, stdout, stderr io.Writer) e
206207
//
207208
// Now running the `envoy-gateway` CLI alternative below by passing `--config-path` to `egConfigPath`.
208209
// Then the agent will read the resources from the file pointed inside the config and start the Envoy process.
210+
runnerErrorHandler := newRunnerErrorHandler(os.Stderr, serverCancel)
211+
server := root.GetRootCommand(runnerErrorHandler)
209212

210-
server := root.GetRootCommand(nil)
211213
// TODO: enable the log by default after the issue is resolved: https://github.com/envoyproxy/gateway/issues/6596
212214
if c.Debug {
213215
server.SetOut(stdout)
@@ -491,6 +493,18 @@ func (runCtx *runCmdContext) tryFindEnvoyListenerPort(gw *gwapiv1.Gateway) int {
491493
return int(gw.Spec.Listeners[0].Port)
492494
}
493495

496+
// newRunnerErrorHandler returns a callback that triggers a graceful shutdown
497+
// (via cancelFunc) when a critical Envoy Gateway runner fails.
498+
func newRunnerErrorHandler(stderr io.Writer, cancelFunc context.CancelFunc) func(string, error) {
499+
return func(runner string, err error) {
500+
if runner == string(egv1a1.LogComponentProviderRunner) ||
501+
runner == string(egv1a1.LogComponentInfrastructureRunner) {
502+
_, _ = fmt.Fprintf(stderr, "exiting on %s runner error: %v\n", runner, err)
503+
cancelFunc()
504+
}
505+
}
506+
}
507+
494508
func maybeResolveHome(p string) string {
495509
if strings.HasPrefix(p, "~/") {
496510
home, err := os.UserHomeDir()

cmd/aigw/run_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,68 @@ func Test_newEnvoyMiddleware(t *testing.T) {
288288
}
289289
}
290290

291+
func Test_newRunnerErrorHandler(t *testing.T) {
292+
tests := []struct {
293+
name string
294+
runner string
295+
expectCancel bool
296+
expectInStderr bool
297+
}{
298+
{
299+
name: "provider runner triggers graceful shutdown",
300+
runner: "provider",
301+
expectCancel: true,
302+
expectInStderr: true,
303+
},
304+
{
305+
name: "infrastructure runner triggers graceful shutdown",
306+
runner: "infrastructure",
307+
expectCancel: true,
308+
expectInStderr: true,
309+
},
310+
{
311+
name: "gateway-api runner does not trigger shutdown",
312+
runner: "gateway-api",
313+
expectCancel: false,
314+
},
315+
{
316+
name: "xds-translator runner does not trigger shutdown",
317+
runner: "xds-translator",
318+
expectCancel: false,
319+
},
320+
{
321+
name: "unknown runner does not trigger shutdown",
322+
runner: "unknown",
323+
expectCancel: false,
324+
},
325+
}
326+
327+
for _, tt := range tests {
328+
t.Run(tt.name, func(t *testing.T) {
329+
ctx, cancel := context.WithCancel(t.Context())
330+
defer cancel()
331+
332+
var stderr bytes.Buffer
333+
handler := newRunnerErrorHandler(&stderr, cancel)
334+
335+
mockErr := errors.New("something went wrong")
336+
handler(tt.runner, mockErr)
337+
338+
if tt.expectCancel {
339+
require.Error(t, ctx.Err(), "context should be cancelled")
340+
} else {
341+
require.NoError(t, ctx.Err(), "context should not be cancelled")
342+
}
343+
if tt.expectInStderr {
344+
require.Contains(t, stderr.String(), tt.runner)
345+
require.Contains(t, stderr.String(), "something went wrong")
346+
} else {
347+
require.Empty(t, stderr.String())
348+
}
349+
})
350+
}
351+
}
352+
291353
func findFlagValue(args []string, flag string) string {
292354
for i, arg := range args {
293355
if arg == flag && i+1 < len(args) {

0 commit comments

Comments
 (0)