From 4e0515ca5ecbb2a2a3b0d2349185b86e5c63b3ca Mon Sep 17 00:00:00 2001 From: Matheus Nogueira Date: Fri, 8 Sep 2023 11:33:00 -0300 Subject: [PATCH] fix: alert about localhost when trigger is running inside container (#3124) * fix: add back container execution detection * fix: check if target is localhost in executor --- server/executor/trigger_executer_worker.go | 71 +++++++++++++++++++ .../trigger_result_processor_worker.go | 28 +------- server/test/trigger/trigger.go | 1 + 3 files changed, 73 insertions(+), 27 deletions(-) diff --git a/server/executor/trigger_executer_worker.go b/server/executor/trigger_executer_worker.go index c425d3f494..9bb0313bc8 100644 --- a/server/executor/trigger_executer_worker.go +++ b/server/executor/trigger_executer_worker.go @@ -2,12 +2,17 @@ package executor import ( "context" + "errors" "fmt" + "net/url" + "os" + "strings" "github.com/kubeshop/tracetest/server/analytics" triggerer "github.com/kubeshop/tracetest/server/executor/trigger" "github.com/kubeshop/tracetest/server/model/events" "github.com/kubeshop/tracetest/server/test" + "github.com/kubeshop/tracetest/server/test/trigger" "go.opentelemetry.io/otel/trace" ) @@ -66,6 +71,15 @@ func (r triggerExecuterWorker) ProcessItem(ctx context.Context, job Job) { response, err := triggererObj.Trigger(ctx, job.Test, &triggerer.TriggerOptions{ TraceID: run.TraceID, }) + if err != nil { + response.Result.Error = &trigger.TriggerError{ + ConnectionError: isConnectionError(err), + RunningOnContainer: isServerRunningInsideContainer(), + TargetsLocalhost: isTargetLocalhost(job.Test.Trigger), + ErrorMessage: err.Error(), + } + } + run = r.handleExecutionResult(run, response, err) run.SpanID = response.SpanID @@ -89,3 +103,60 @@ func (r triggerExecuterWorker) handleExecutionResult(run test.Run, response trig return run.SuccessfullyTriggered() } + +func isConnectionError(err error) bool { + for err != nil { + // a dial error means we couldn't open a TCP connection (either host is not available or DNS doesn't exist) + if strings.HasPrefix(err.Error(), "dial ") { + return true + } + + // it means a trigger timeout + if errors.Is(err, context.DeadlineExceeded) { + return true + } + + err = errors.Unwrap(err) + } + + return false +} + +func isTargetLocalhost(t trigger.Trigger) bool { + var endpoint string + switch t.Type { + case trigger.TriggerTypeHTTP: + endpoint = t.HTTP.URL + case trigger.TriggerTypeGRPC: + endpoint = t.GRPC.Address + } + + url, err := url.Parse(endpoint) + if err != nil { + return false + } + + // removes port + host := url.Host + colonPosition := strings.Index(url.Host, ":") + if colonPosition >= 0 { + host = host[0:colonPosition] + } + + return host == "localhost" || host == "127.0.0.1" +} + +func isServerRunningInsideContainer() bool { + // Check if running on Docker + // Reference: https://paulbradley.org/indocker/ + if _, err := os.Stat("/.dockerenv"); err == nil { + return true + } + + // Check if running on k8s + if os.Getenv("KUBERNETES_SERVICE_HOST") != "" { + return true + } + + return false +} diff --git a/server/executor/trigger_result_processor_worker.go b/server/executor/trigger_result_processor_worker.go index b79c73b9c8..28882037ce 100644 --- a/server/executor/trigger_result_processor_worker.go +++ b/server/executor/trigger_result_processor_worker.go @@ -3,8 +3,6 @@ package executor import ( "context" "fmt" - "net/url" - "strings" "github.com/kubeshop/tracetest/server/model" "github.com/kubeshop/tracetest/server/model/events" @@ -64,7 +62,7 @@ func (r triggerResultProcessorWorker) ProcessItem(ctx context.Context, job Job) if triggerResult.Error.ConnectionError { r.emitUnreachableEndpointEvent(ctx, job, err) - if isTargetLocalhost(job) && triggerResult.Error.RunningOnContainer { + if triggerResult.Error.TargetsLocalhost && triggerResult.Error.RunningOnContainer { r.emitMismatchEndpointEvent(ctx, job, err) } } @@ -111,27 +109,3 @@ func (r triggerResultProcessorWorker) emitMismatchEndpointEvent(ctx context.Cont r.handleError(job.Run, emitErr) } } - -func isTargetLocalhost(job Job) bool { - var endpoint string - switch job.Test.Trigger.Type { - case trigger.TriggerTypeHTTP: - endpoint = job.Test.Trigger.HTTP.URL - case trigger.TriggerTypeGRPC: - endpoint = job.Test.Trigger.GRPC.Address - } - - url, err := url.Parse(endpoint) - if err != nil { - return false - } - - // removes port - host := url.Host - colonPosition := strings.Index(url.Host, ":") - if colonPosition >= 0 { - host = host[0:colonPosition] - } - - return host == "localhost" || host == "127.0.0.1" -} diff --git a/server/test/trigger/trigger.go b/server/test/trigger/trigger.go index 0809ae629a..025834cbea 100644 --- a/server/test/trigger/trigger.go +++ b/server/test/trigger/trigger.go @@ -25,6 +25,7 @@ type ( TriggerError struct { ConnectionError bool `json:"connectionError"` RunningOnContainer bool `json:"runningOnContainer"` + TargetsLocalhost bool `json:"targetsLocalhost"` ErrorMessage string `json:"message"` } )