mirror of
https://github.com/containous/traefik.git
synced 2024-12-22 13:34:03 +03:00
551 lines
24 KiB
Go
551 lines
24 KiB
Go
package integration
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
"github.com/tidwall/gjson"
|
|
"github.com/traefik/traefik/v3/integration/try"
|
|
)
|
|
|
|
type TracingSuite struct {
|
|
BaseSuite
|
|
whoamiIP string
|
|
whoamiPort int
|
|
tempoIP string
|
|
otelCollectorIP string
|
|
}
|
|
|
|
func TestTracingSuite(t *testing.T) {
|
|
suite.Run(t, new(TracingSuite))
|
|
}
|
|
|
|
type TracingTemplate struct {
|
|
WhoamiIP string
|
|
WhoamiPort int
|
|
IP string
|
|
TraceContextHeaderName string
|
|
IsHTTP bool
|
|
}
|
|
|
|
func (s *TracingSuite) SetupSuite() {
|
|
s.BaseSuite.SetupSuite()
|
|
|
|
s.createComposeProject("tracing")
|
|
s.composeUp()
|
|
|
|
s.whoamiIP = s.getComposeServiceIP("whoami")
|
|
s.whoamiPort = 80
|
|
|
|
// Wait for whoami to turn ready.
|
|
err := try.GetRequest("http://"+s.whoamiIP+":80", 30*time.Second, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
s.otelCollectorIP = s.getComposeServiceIP("otel-collector")
|
|
|
|
// Wait for otel collector to turn ready.
|
|
err = try.GetRequest("http://"+s.otelCollectorIP+":13133/", 30*time.Second, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
}
|
|
|
|
func (s *TracingSuite) TearDownSuite() {
|
|
s.BaseSuite.TearDownSuite()
|
|
}
|
|
|
|
func (s *TracingSuite) SetupTest() {
|
|
s.composeUp("tempo")
|
|
|
|
s.tempoIP = s.getComposeServiceIP("tempo")
|
|
|
|
// Wait for tempo to turn ready.
|
|
err := try.GetRequest("http://"+s.tempoIP+":3200/ready", 30*time.Second, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
}
|
|
|
|
func (s *TracingSuite) TearDownTest() {
|
|
s.composeStop("tempo")
|
|
}
|
|
|
|
func (s *TracingSuite) TestOpentelemetryBasic_HTTP() {
|
|
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
|
WhoamiIP: s.whoamiIP,
|
|
WhoamiPort: s.whoamiPort,
|
|
IP: s.otelCollectorIP,
|
|
IsHTTP: true,
|
|
})
|
|
|
|
s.traefikCmd(withConfigFile(file))
|
|
|
|
// wait for traefik
|
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/basic", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
contains := []map[string]string{
|
|
{
|
|
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
|
|
|
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint",
|
|
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/basic",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
|
|
|
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
|
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.2.name": "Service",
|
|
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.3.name": "ReverseProxy",
|
|
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_CLIENT",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.scheme\").value.stringValue": "http",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
|
},
|
|
}
|
|
|
|
s.checkTraceContent(contains)
|
|
}
|
|
|
|
func (s *TracingSuite) TestOpentelemetryBasic_gRPC() {
|
|
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
|
WhoamiIP: s.whoamiIP,
|
|
WhoamiPort: s.whoamiPort,
|
|
IP: s.otelCollectorIP,
|
|
IsHTTP: false,
|
|
})
|
|
defer os.Remove(file)
|
|
|
|
s.traefikCmd(withConfigFile(file))
|
|
|
|
// wait for traefik
|
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/basic", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
contains := []map[string]string{
|
|
{
|
|
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
|
|
|
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint",
|
|
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/basic",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
|
|
|
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
|
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.2.name": "Service",
|
|
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.3.name": "ReverseProxy",
|
|
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_CLIENT",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.scheme\").value.stringValue": "http",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
|
},
|
|
}
|
|
|
|
s.checkTraceContent(contains)
|
|
}
|
|
|
|
func (s *TracingSuite) TestOpentelemetryRateLimit() {
|
|
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
|
WhoamiIP: s.whoamiIP,
|
|
WhoamiPort: s.whoamiPort,
|
|
IP: s.otelCollectorIP,
|
|
})
|
|
defer os.Remove(file)
|
|
|
|
s.traefikCmd(withConfigFile(file))
|
|
|
|
// wait for traefik
|
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
|
require.NoError(s.T(), err)
|
|
|
|
// sleep for 4 seconds to be certain the configured time period has elapsed
|
|
// then test another request and verify a 200 status code
|
|
time.Sleep(4 * time.Second)
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
// continue requests at 3 second intervals to test the other rate limit time period
|
|
time.Sleep(3 * time.Second)
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
time.Sleep(3 * time.Second)
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
|
require.NoError(s.T(), err)
|
|
|
|
contains := []map[string]string{
|
|
{
|
|
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
|
|
|
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint",
|
|
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
|
|
|
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
|
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.2.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.3.name": "RateLimiter",
|
|
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.4.name": "Service",
|
|
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.5.name": "ReverseProxy",
|
|
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_CLIENT",
|
|
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"url.scheme\").value.stringValue": "http",
|
|
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
|
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
|
},
|
|
{
|
|
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
|
|
|
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint",
|
|
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "429",
|
|
|
|
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
|
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.2.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.3.name": "RateLimiter",
|
|
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.4.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.resend_count\").value.intValue": "1",
|
|
|
|
"batches.0.scopeSpans.0.spans.5.name": "RateLimiter",
|
|
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.6.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.resend_count\").value.intValue": "2",
|
|
|
|
"batches.0.scopeSpans.0.spans.7.name": "RateLimiter",
|
|
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
|
},
|
|
}
|
|
|
|
s.checkTraceContent(contains)
|
|
}
|
|
|
|
func (s *TracingSuite) TestOpentelemetryRetry() {
|
|
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
|
WhoamiIP: s.whoamiIP,
|
|
WhoamiPort: 81,
|
|
IP: s.otelCollectorIP,
|
|
})
|
|
defer os.Remove(file)
|
|
|
|
s.traefikCmd(withConfigFile(file))
|
|
|
|
// wait for traefik
|
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("basic-auth"))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
|
|
require.NoError(s.T(), err)
|
|
|
|
contains := []map[string]string{
|
|
{
|
|
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
|
|
|
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/retry",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
|
|
"batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR",
|
|
|
|
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
|
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router2@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.2.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.3.name": "Service",
|
|
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.4.name": "ReverseProxy",
|
|
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_CLIENT",
|
|
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"url.scheme\").value.stringValue": "http",
|
|
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
|
|
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
|
|
|
"batches.0.scopeSpans.0.spans.5.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.resend_count\").value.intValue": "1",
|
|
|
|
"batches.0.scopeSpans.0.spans.6.name": "Service",
|
|
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.7.name": "ReverseProxy",
|
|
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_CLIENT",
|
|
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.scheme\").value.stringValue": "http",
|
|
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
|
|
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
|
|
|
"batches.0.scopeSpans.0.spans.8.name": "Retry",
|
|
"batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.resend_count\").value.intValue": "2",
|
|
|
|
"batches.0.scopeSpans.0.spans.9.name": "Service",
|
|
"batches.0.scopeSpans.0.spans.9.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.9.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.10.name": "ReverseProxy",
|
|
"batches.0.scopeSpans.0.spans.10.kind": "SPAN_KIND_CLIENT",
|
|
"batches.0.scopeSpans.0.spans.10.attributes.#(key=\"url.scheme\").value.stringValue": "http",
|
|
"batches.0.scopeSpans.0.spans.10.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
|
|
"batches.0.scopeSpans.0.spans.10.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
|
},
|
|
}
|
|
|
|
s.checkTraceContent(contains)
|
|
}
|
|
|
|
func (s *TracingSuite) TestOpentelemetryAuth() {
|
|
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
|
WhoamiIP: s.whoamiIP,
|
|
WhoamiPort: s.whoamiPort,
|
|
IP: s.otelCollectorIP,
|
|
})
|
|
defer os.Remove(file)
|
|
|
|
s.traefikCmd(withConfigFile(file))
|
|
|
|
// wait for traefik
|
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
|
|
require.NoError(s.T(), err)
|
|
|
|
contains := []map[string]string{
|
|
{
|
|
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
|
|
|
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/auth",
|
|
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "401",
|
|
|
|
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
|
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
|
|
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
|
|
|
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
|
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
|
|
},
|
|
}
|
|
|
|
s.checkTraceContent(contains)
|
|
}
|
|
|
|
func (s *TracingSuite) TestNoInternals() {
|
|
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
|
WhoamiIP: s.whoamiIP,
|
|
WhoamiPort: s.whoamiPort,
|
|
IP: s.otelCollectorIP,
|
|
IsHTTP: true,
|
|
})
|
|
|
|
s.traefikCmd(withConfigFile(file))
|
|
|
|
// wait for traefik
|
|
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("basic-auth"))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
err = try.GetRequest("http://127.0.0.1:8000/ping", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
err = try.GetRequest("http://127.0.0.1:8080/ping", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
require.NoError(s.T(), err)
|
|
|
|
baseURL, err := url.Parse("http://" + s.tempoIP + ":3200/api/search")
|
|
require.NoError(s.T(), err)
|
|
|
|
req := &http.Request{
|
|
Method: http.MethodGet,
|
|
URL: baseURL,
|
|
}
|
|
// Wait for traces to be available.
|
|
time.Sleep(10 * time.Second)
|
|
resp, err := try.Response(req, 5*time.Second)
|
|
require.NoError(s.T(), err)
|
|
|
|
out := &TraceResponse{}
|
|
content, err := io.ReadAll(resp.Body)
|
|
require.NoError(s.T(), err)
|
|
err = json.Unmarshal(content, &out)
|
|
require.NoError(s.T(), err)
|
|
|
|
s.NotEmptyf(len(out.Traces), "expected at least one trace")
|
|
|
|
for _, t := range out.Traces {
|
|
baseURL, err := url.Parse("http://" + s.tempoIP + ":3200/api/traces/" + t.TraceID)
|
|
require.NoError(s.T(), err)
|
|
|
|
req := &http.Request{
|
|
Method: http.MethodGet,
|
|
URL: baseURL,
|
|
}
|
|
|
|
resp, err := try.Response(req, 5*time.Second)
|
|
require.NoError(s.T(), err)
|
|
|
|
content, err := io.ReadAll(resp.Body)
|
|
require.NoError(s.T(), err)
|
|
|
|
require.NotContains(s.T(), content, "@internal")
|
|
}
|
|
}
|
|
|
|
func (s *TracingSuite) checkTraceContent(expectedJSON []map[string]string) {
|
|
s.T().Helper()
|
|
|
|
baseURL, err := url.Parse("http://" + s.tempoIP + ":3200/api/search")
|
|
require.NoError(s.T(), err)
|
|
|
|
req := &http.Request{
|
|
Method: http.MethodGet,
|
|
URL: baseURL,
|
|
}
|
|
// Wait for traces to be available.
|
|
time.Sleep(10 * time.Second)
|
|
resp, err := try.Response(req, 5*time.Second)
|
|
require.NoError(s.T(), err)
|
|
|
|
out := &TraceResponse{}
|
|
content, err := io.ReadAll(resp.Body)
|
|
require.NoError(s.T(), err)
|
|
err = json.Unmarshal(content, &out)
|
|
require.NoError(s.T(), err)
|
|
|
|
s.NotEmptyf(len(out.Traces), "expected at least one trace")
|
|
|
|
var contents []string
|
|
for _, t := range out.Traces {
|
|
baseURL, err := url.Parse("http://" + s.tempoIP + ":3200/api/traces/" + t.TraceID)
|
|
require.NoError(s.T(), err)
|
|
|
|
req := &http.Request{
|
|
Method: http.MethodGet,
|
|
URL: baseURL,
|
|
}
|
|
|
|
resp, err := try.Response(req, 5*time.Second)
|
|
require.NoError(s.T(), err)
|
|
|
|
content, err := io.ReadAll(resp.Body)
|
|
require.NoError(s.T(), err)
|
|
|
|
contents = append(contents, string(content))
|
|
}
|
|
|
|
for _, expected := range expectedJSON {
|
|
containsAll(expected, contents)
|
|
}
|
|
}
|
|
|
|
func containsAll(expectedJSON map[string]string, contents []string) {
|
|
for k, v := range expectedJSON {
|
|
found := false
|
|
for _, content := range contents {
|
|
if gjson.Get(content, k).String() == v {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
log.Info().Msgf("[" + strings.Join(contents, ",") + "]")
|
|
log.Error().Msgf("missing element: \nKey: %q\nValue: %q ", k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TraceResponse contains a list of traces.
|
|
type TraceResponse struct {
|
|
Traces []Trace `json:"traces"`
|
|
}
|
|
|
|
// Trace represents a simplified grafana tempo trace.
|
|
type Trace struct {
|
|
TraceID string `json:"traceID"`
|
|
}
|