mirror of
https://github.com/traefik/traefik.git
synced 2026-05-04 20:06:21 +02:00
Add Kubernetes Ingress logs fields
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
parent
d31ce5df13
commit
64495e424c
@ -384,6 +384,10 @@ Below the fields displayed with the generic CLF format:
|
||||
| <a id="opt-TLSVersion" href="#opt-TLSVersion" title="#opt-TLSVersion">`TLSVersion`</a> | The TLS version used by the connection (e.g. `1.2`) (if connection is TLS). |
|
||||
| <a id="opt-TLSCipher" href="#opt-TLSCipher" title="#opt-TLSCipher">`TLSCipher`</a> | The TLS cipher used by the connection (e.g. `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA`) (if connection is TLS). |
|
||||
| <a id="opt-TLSClientSubject" href="#opt-TLSClientSubject" title="#opt-TLSClientSubject">`TLSClientSubject`</a> | The string representation of the TLS client certificate's Subject (e.g. `CN=username,O=organization`). |
|
||||
| <a id="opt-KubernetesIngressNamespace" href="#opt-KubernetesIngressNamespace" title="#opt-KubernetesIngressNamespace">`KubernetesIngressNamespace`</a> | The namespace of the Kubernetes Ingress resource the router handles. Only available with the Kubernetes Ingress and Kubernetes Ingress Nginx providers. |
|
||||
| <a id="opt-KubernetesIngressName" href="#opt-KubernetesIngressName" title="#opt-KubernetesIngressName">`KubernetesIngressName`</a> | The name of the Kubernetes Ingress resource the router handles. Only available with the Kubernetes Ingress and Kubernetes Ingress Nginx providers. |
|
||||
| <a id="opt-KubernetesServiceName" href="#opt-KubernetesServiceName" title="#opt-KubernetesServiceName">`KubernetesServiceName`</a> | The name of the Kubernetes Service associated with the Ingress the router handles. Only available with the Kubernetes Ingress and Kubernetes Ingress Nginx providers. |
|
||||
| <a id="opt-KubernetesServicePort" href="#opt-KubernetesServicePort" title="#opt-KubernetesServicePort">`KubernetesServicePort`</a> | The port of the Kubernetes Service associated with the Ingress the router handles. Only available with the Kubernetes Ingress and Kubernetes Ingress Nginx providers. |
|
||||
|
||||
### Log Rotation
|
||||
|
||||
|
||||
@ -111,13 +111,13 @@ func (s *K8sSuite) TestGatewayConfiguration() {
|
||||
s.testConfiguration("testdata/rawdata-gateway.json", "8080")
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TestIngressclass() {
|
||||
func (s *K8sSuite) TestIngressClass() {
|
||||
s.traefikCmd(withConfigFile("fixtures/k8s_ingressclass.toml"))
|
||||
|
||||
s.testConfiguration("testdata/rawdata-ingressclass.json", "8080")
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TestDisableIngressclassLookup() {
|
||||
func (s *K8sSuite) TestDisableIngressClassLookup() {
|
||||
s.traefikCmd(withConfigFile("fixtures/k8s_ingressclass_disabled.toml"))
|
||||
|
||||
s.testConfiguration("testdata/rawdata-ingressclass-disabled.json", "8080")
|
||||
|
||||
@ -47,13 +47,21 @@
|
||||
"web"
|
||||
],
|
||||
"service": "default-whoami-http",
|
||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||
"rule": "Host(\"whoami.test\") \u0026\u0026 PathPrefix(\"/whoami\")",
|
||||
"priority": 44,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
"traceVerbosity": "minimal",
|
||||
"metadata": {
|
||||
"ingress": {
|
||||
"namespace": "default",
|
||||
"ingressName": "test.ingress",
|
||||
"serviceName": "whoami",
|
||||
"servicePort": "http"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
|
||||
48
integration/testdata/rawdata-ingress.json
vendored
48
integration/testdata/rawdata-ingress.json
vendored
@ -47,13 +47,21 @@
|
||||
"web"
|
||||
],
|
||||
"service": "default-whoami-http",
|
||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||
"rule": "Host(\"whoami.test.https\") \u0026\u0026 PathPrefix(\"/whoami\")",
|
||||
"priority": 50,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
"traceVerbosity": "minimal",
|
||||
"metadata": {
|
||||
"ingress": {
|
||||
"namespace": "default",
|
||||
"ingressName": "test.ingress.https",
|
||||
"serviceName": "whoami",
|
||||
"servicePort": "http"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
@ -65,13 +73,21 @@
|
||||
"web"
|
||||
],
|
||||
"service": "default-whoami-http",
|
||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||
"rule": "Host(\"whoami.test\") \u0026\u0026 PathPrefix(\"/whoami\")",
|
||||
"priority": 44,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
"traceVerbosity": "minimal",
|
||||
"metadata": {
|
||||
"ingress": {
|
||||
"namespace": "default",
|
||||
"ingressName": "test.ingress",
|
||||
"serviceName": "whoami",
|
||||
"servicePort": "http"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
@ -83,13 +99,21 @@
|
||||
"web"
|
||||
],
|
||||
"service": "default-whoami-80",
|
||||
"rule": "Host(`whoami.test.drop`) \u0026\u0026 PathPrefix(`/drop`)",
|
||||
"rule": "Host(\"whoami.test.drop\") \u0026\u0026 PathPrefix(\"/drop\")",
|
||||
"priority": 47,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
"traceVerbosity": "minimal",
|
||||
"metadata": {
|
||||
"ingress": {
|
||||
"namespace": "default",
|
||||
"ingressName": "whoami-drop-route",
|
||||
"serviceName": "whoami",
|
||||
"servicePort": "80"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
@ -101,13 +125,21 @@
|
||||
"web"
|
||||
],
|
||||
"service": "default-whoami-80",
|
||||
"rule": "Host(`whoami.test.keep`) \u0026\u0026 PathPrefix(`/keep`)",
|
||||
"rule": "Host(\"whoami.test.keep\") \u0026\u0026 PathPrefix(\"/keep\")",
|
||||
"priority": 47,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
"traceVerbosity": "minimal",
|
||||
"metadata": {
|
||||
"ingress": {
|
||||
"namespace": "default",
|
||||
"ingressName": "whoami-keep-route",
|
||||
"serviceName": "whoami",
|
||||
"servicePort": "80"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
|
||||
12
integration/testdata/rawdata-ingressclass.json
vendored
12
integration/testdata/rawdata-ingressclass.json
vendored
@ -47,13 +47,21 @@
|
||||
"web"
|
||||
],
|
||||
"service": "default-whoami-80",
|
||||
"rule": "Host(`whoami.test.keep`) \u0026\u0026 PathPrefix(`/keep`)",
|
||||
"rule": "Host(\"whoami.test.keep\") \u0026\u0026 PathPrefix(\"/keep\")",
|
||||
"priority": 47,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
"traceVerbosity": "minimal",
|
||||
"metadata": {
|
||||
"ingress": {
|
||||
"namespace": "default",
|
||||
"ingressName": "whoami-keep-route",
|
||||
"serviceName": "whoami",
|
||||
"servicePort": "80"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
|
||||
@ -168,6 +168,10 @@ type RouterObservabilityConfig struct {
|
||||
// +kubebuilder:validation:Enum=minimal;detailed
|
||||
// +kubebuilder:default=minimal
|
||||
TraceVerbosity otypes.TracingVerbosity `json:"traceVerbosity,omitempty" toml:"traceVerbosity,omitempty" yaml:"traceVerbosity,omitempty" export:"true"`
|
||||
|
||||
// Metadata holds the metadata for this router.
|
||||
// Metadata cannot be user-defined for now.
|
||||
Metadata *ObservabilityMetadata `json:"metadata,omitempty" toml:"-" yaml:"-" label:"-" file:"-" kv:"-"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a RouterObservabilityConfig.
|
||||
@ -177,6 +181,23 @@ func (r *RouterObservabilityConfig) SetDefaults() {
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ObservabilityMetadata holds the observability metadata configuration.
|
||||
type ObservabilityMetadata struct {
|
||||
Ingress *KubernetesIngressMetadata `json:"ingress,omitempty" toml:"-" yaml:"-" label:"-" file:"-" kv:"-"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// KubernetesIngressMetadata holds the Kubernetes Ingress metadata.
|
||||
type KubernetesIngressMetadata struct {
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
IngressName string `json:"ingressName,omitempty"`
|
||||
ServiceName string `json:"serviceName,omitempty"`
|
||||
ServicePort string `json:"servicePort,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Mirroring holds the Mirroring configuration.
|
||||
type Mirroring struct {
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
|
||||
@ -957,6 +957,22 @@ func (in *InFlightReq) DeepCopy() *InFlightReq {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubernetesIngressMetadata) DeepCopyInto(out *KubernetesIngressMetadata) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesIngressMetadata.
|
||||
func (in *KubernetesIngressMetadata) DeepCopy() *KubernetesIngressMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubernetesIngressMetadata)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Message) DeepCopyInto(out *Message) {
|
||||
*out = *in
|
||||
@ -1245,6 +1261,27 @@ func (in *Model) DeepCopy() *Model {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ObservabilityMetadata) DeepCopyInto(out *ObservabilityMetadata) {
|
||||
*out = *in
|
||||
if in.Ingress != nil {
|
||||
in, out := &in.Ingress, &out.Ingress
|
||||
*out = new(KubernetesIngressMetadata)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObservabilityMetadata.
|
||||
func (in *ObservabilityMetadata) DeepCopy() *ObservabilityMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ObservabilityMetadata)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PassTLSClientCert) DeepCopyInto(out *PassTLSClientCert) {
|
||||
*out = *in
|
||||
@ -1614,6 +1651,11 @@ func (in *RouterObservabilityConfig) DeepCopyInto(out *RouterObservabilityConfig
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.Metadata != nil {
|
||||
in, out := &in.Metadata, &out.Metadata
|
||||
*out = new(ObservabilityMetadata)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +87,17 @@ const (
|
||||
OTelTraceID = "trace_id"
|
||||
// OTelSpanID is the OTel-conformant log attribute for the span identifier.
|
||||
OTelSpanID = "span_id"
|
||||
|
||||
// Kubernetes Ingress fields.
|
||||
|
||||
// KubernetesIngressNamespace is the namespace of the Kubernetes Ingress resource the router handles.
|
||||
KubernetesIngressNamespace = "KubernetesIngressNamespace"
|
||||
// KubernetesIngressName is the name of the Kubernetes Ingress resource the router handles.
|
||||
KubernetesIngressName = "KubernetesIngressName"
|
||||
// KubernetesServiceName is the name of the Kubernetes service associated with Ingress the router handles.
|
||||
KubernetesServiceName = "KubernetesServiceName"
|
||||
// KubernetesServicePort is the port of the Kubernetes service associated with Ingress the router handles.
|
||||
KubernetesServicePort = "KubernetesServicePort"
|
||||
)
|
||||
|
||||
// These are written out in the default case when no config is provided to specify keys of interest.
|
||||
@ -94,11 +105,21 @@ var defaultCoreKeys = [...]string{
|
||||
StartUTC,
|
||||
Duration,
|
||||
RouterName,
|
||||
ServiceAddr,
|
||||
ServiceName,
|
||||
ServiceURL,
|
||||
ClientAddr,
|
||||
ClientHost,
|
||||
ClientPort,
|
||||
ClientUsername,
|
||||
GzipRatio,
|
||||
StartLocal,
|
||||
Overhead,
|
||||
RetryAttempts,
|
||||
TLSVersion,
|
||||
TLSCipher,
|
||||
TLSClientSubject,
|
||||
RequestAddr,
|
||||
RequestHost,
|
||||
RequestPort,
|
||||
RequestMethod,
|
||||
@ -121,18 +142,6 @@ func init() {
|
||||
for _, k := range defaultCoreKeys {
|
||||
allCoreKeys[k] = struct{}{}
|
||||
}
|
||||
allCoreKeys[ServiceAddr] = struct{}{}
|
||||
allCoreKeys[ClientAddr] = struct{}{}
|
||||
allCoreKeys[RequestAddr] = struct{}{}
|
||||
allCoreKeys[GzipRatio] = struct{}{}
|
||||
allCoreKeys[StartLocal] = struct{}{}
|
||||
allCoreKeys[Overhead] = struct{}{}
|
||||
allCoreKeys[RetryAttempts] = struct{}{}
|
||||
allCoreKeys[TLSVersion] = struct{}{}
|
||||
allCoreKeys[TLSCipher] = struct{}{}
|
||||
allCoreKeys[TLSClientSubject] = struct{}{}
|
||||
allCoreKeys[OTelTraceID] = struct{}{}
|
||||
allCoreKeys[OTelSpanID] = struct{}{}
|
||||
}
|
||||
|
||||
// CoreLogData holds the fields computed from the request/response.
|
||||
|
||||
@ -204,6 +204,15 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
||||
},
|
||||
}
|
||||
|
||||
if metadata := observability.GetObservabilityMetadata(req.Context()); metadata != nil {
|
||||
if metadata.Ingress != nil {
|
||||
logDataTable.Core[KubernetesIngressNamespace] = metadata.Ingress.Namespace
|
||||
logDataTable.Core[KubernetesIngressName] = metadata.Ingress.IngressName
|
||||
logDataTable.Core[KubernetesServiceName] = metadata.Ingress.ServiceName
|
||||
logDataTable.Core[KubernetesServicePort] = metadata.Ingress.ServicePort
|
||||
}
|
||||
}
|
||||
|
||||
if span := trace.SpanFromContext(req.Context()); span != nil {
|
||||
spanContext := span.SpanContext()
|
||||
if spanContext.HasTraceID() && spanContext.HasSpanID() {
|
||||
|
||||
@ -25,6 +25,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/capture"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
|
||||
otypes "github.com/traefik/traefik/v3/pkg/observability/types"
|
||||
@ -452,7 +453,7 @@ func TestLoggerHeaderFields(t *testing.T) {
|
||||
func TestCommonLogger(t *testing.T) {
|
||||
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
||||
config := &otypes.AccessLog{FilePath: logFilePath, Format: CommonFormat}
|
||||
doLogging(t, config, false)
|
||||
doLogging(t, config, false, false)
|
||||
|
||||
logData, err := os.ReadFile(logFilePath)
|
||||
require.NoError(t, err)
|
||||
@ -464,7 +465,7 @@ func TestCommonLogger(t *testing.T) {
|
||||
func TestCommonLoggerWithBufferingSize(t *testing.T) {
|
||||
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
||||
config := &otypes.AccessLog{FilePath: logFilePath, Format: CommonFormat, BufferingSize: 1024}
|
||||
doLogging(t, config, false)
|
||||
doLogging(t, config, false, false)
|
||||
|
||||
// wait a bit for the buffer to be written in the file.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
@ -479,7 +480,7 @@ func TestCommonLoggerWithBufferingSize(t *testing.T) {
|
||||
func TestLoggerGenericCLF(t *testing.T) {
|
||||
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
||||
config := &otypes.AccessLog{FilePath: logFilePath, Format: GenericCLFFormat}
|
||||
doLogging(t, config, false)
|
||||
doLogging(t, config, false, false)
|
||||
|
||||
logData, err := os.ReadFile(logFilePath)
|
||||
require.NoError(t, err)
|
||||
@ -491,7 +492,7 @@ func TestLoggerGenericCLF(t *testing.T) {
|
||||
func TestLoggerGenericCLFWithBufferingSize(t *testing.T) {
|
||||
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
||||
config := &otypes.AccessLog{FilePath: logFilePath, Format: GenericCLFFormat, BufferingSize: 1024}
|
||||
doLogging(t, config, false)
|
||||
doLogging(t, config, false, false)
|
||||
|
||||
// wait a bit for the buffer to be written in the file.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
@ -541,6 +542,7 @@ func TestLoggerJSON(t *testing.T) {
|
||||
config *otypes.AccessLog
|
||||
tls bool
|
||||
tracing bool
|
||||
metadata bool
|
||||
expected map[string]func(t *testing.T, value any)
|
||||
}{
|
||||
{
|
||||
@ -626,6 +628,50 @@ func TestLoggerJSON(t *testing.T) {
|
||||
OTelSpanID: assertString("0100000000000000"),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "default config with metadata",
|
||||
config: &otypes.AccessLog{
|
||||
FilePath: "",
|
||||
Format: JSONFormat,
|
||||
},
|
||||
metadata: true,
|
||||
expected: map[string]func(t *testing.T, value any){
|
||||
RequestContentSize: assertFloat64(0),
|
||||
RequestHost: assertString(testHostname),
|
||||
RequestAddr: assertString(testHostname),
|
||||
RequestMethod: assertString(testMethod),
|
||||
RequestPath: assertString(testPath),
|
||||
RequestProtocol: assertString(testProto),
|
||||
RequestScheme: assertString(testScheme),
|
||||
RequestPort: assertString("-"),
|
||||
DownstreamStatus: assertFloat64(float64(testStatus)),
|
||||
DownstreamContentSize: assertFloat64(float64(len(testContent))),
|
||||
OriginContentSize: assertFloat64(float64(len(testContent))),
|
||||
OriginStatus: assertFloat64(float64(testStatus)),
|
||||
RequestRefererHeader: assertString(testReferer),
|
||||
RequestUserAgentHeader: assertString(testUserAgent),
|
||||
RouterName: assertString(testRouterName),
|
||||
ServiceURL: assertString(testServiceName),
|
||||
ClientUsername: assertString(testUsername),
|
||||
ClientHost: assertString(testHostname),
|
||||
ClientPort: assertString(strconv.Itoa(testPort)),
|
||||
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
|
||||
"level": assertString("info"),
|
||||
"msg": assertString(""),
|
||||
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
|
||||
RequestCount: assertFloat64NotZero(),
|
||||
Duration: assertFloat64NotZero(),
|
||||
Overhead: assertFloat64NotZero(),
|
||||
RetryAttempts: assertFloat64(float64(testRetryAttempts)),
|
||||
"time": assertNotEmpty(),
|
||||
"StartLocal": assertNotEmpty(),
|
||||
"StartUTC": assertNotEmpty(),
|
||||
KubernetesIngressNamespace: assertString("test-namespace"),
|
||||
KubernetesIngressName: assertString("test-ingress"),
|
||||
KubernetesServiceName: assertString("test-service"),
|
||||
KubernetesServicePort: assertString("test-port"),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "default config, with TLS request",
|
||||
config: &otypes.AccessLog{
|
||||
@ -788,9 +834,9 @@ func TestLoggerJSON(t *testing.T) {
|
||||
|
||||
test.config.FilePath = logFilePath
|
||||
if test.tls {
|
||||
doLoggingTLS(t, test.config, test.tracing)
|
||||
doLoggingTLS(t, test.config, test.tracing, test.metadata)
|
||||
} else {
|
||||
doLogging(t, test.config, test.tracing)
|
||||
doLogging(t, test.config, test.tracing, test.metadata)
|
||||
}
|
||||
|
||||
logData, err := os.ReadFile(logFilePath)
|
||||
@ -1062,7 +1108,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
|
||||
file, restoreStdout := captureStdout(t)
|
||||
defer restoreStdout()
|
||||
|
||||
doLogging(t, test.config, false)
|
||||
doLogging(t, test.config, false, false)
|
||||
|
||||
written, err := os.ReadFile(file.Name())
|
||||
require.NoError(t, err, "unable to read captured stdout from file")
|
||||
@ -1150,7 +1196,7 @@ func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {
|
||||
return file, restoreStdout
|
||||
}
|
||||
|
||||
func doLoggingTLSOpt(t *testing.T, config *otypes.AccessLog, enableTLS, tracing bool) {
|
||||
func doLoggingTLSOpt(t *testing.T, config *otypes.AccessLog, enableTLS, tracing, metadata bool) {
|
||||
t.Helper()
|
||||
logger, err := NewHandler(t.Context(), config)
|
||||
require.NoError(t, err)
|
||||
@ -1199,9 +1245,22 @@ func doLoggingTLSOpt(t *testing.T, config *otypes.AccessLog, enableTLS, tracing
|
||||
|
||||
// Injection of the observability variables in the request context.
|
||||
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
|
||||
return observability.WithObservabilityHandler(next, observability.Observability{
|
||||
obs := observability.Observability{
|
||||
AccessLogsEnabled: true,
|
||||
}), nil
|
||||
}
|
||||
|
||||
if metadata {
|
||||
obs.Metadata = &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "test-namespace",
|
||||
IngressName: "test-ingress",
|
||||
ServiceName: "test-service",
|
||||
ServicePort: "test-port",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return observability.WithObservabilityHandler(next, obs), nil
|
||||
})
|
||||
|
||||
chain = chain.Append(logger.AliceConstructor())
|
||||
@ -1211,16 +1270,16 @@ func doLoggingTLSOpt(t *testing.T, config *otypes.AccessLog, enableTLS, tracing
|
||||
handler.ServeHTTP(httptest.NewRecorder(), req)
|
||||
}
|
||||
|
||||
func doLoggingTLS(t *testing.T, config *otypes.AccessLog, tracing bool) {
|
||||
func doLoggingTLS(t *testing.T, config *otypes.AccessLog, tracing, metadata bool) {
|
||||
t.Helper()
|
||||
|
||||
doLoggingTLSOpt(t, config, true, tracing)
|
||||
doLoggingTLSOpt(t, config, true, tracing, metadata)
|
||||
}
|
||||
|
||||
func doLogging(t *testing.T, config *otypes.AccessLog, tracing bool) {
|
||||
func doLogging(t *testing.T, config *otypes.AccessLog, tracing, metadata bool) {
|
||||
t.Helper()
|
||||
|
||||
doLoggingTLSOpt(t, config, false, tracing)
|
||||
doLoggingTLSOpt(t, config, false, tracing, metadata)
|
||||
}
|
||||
|
||||
func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
@ -19,6 +20,7 @@ type Observability struct {
|
||||
SemConvMetricsEnabled bool
|
||||
TracingEnabled bool
|
||||
DetailedTracingEnabled bool
|
||||
Metadata *dynamic.ObservabilityMetadata
|
||||
}
|
||||
|
||||
// WithObservabilityHandler sets the observability state in the context for the next handler.
|
||||
@ -64,6 +66,15 @@ func DetailedTracingEnabled(ctx context.Context) bool {
|
||||
return ok && obs.DetailedTracingEnabled
|
||||
}
|
||||
|
||||
// GetObservabilityMetadata returns the observability metadata.
|
||||
func GetObservabilityMetadata(ctx context.Context) *dynamic.ObservabilityMetadata {
|
||||
obs, ok := ctx.Value(observabilityKey).(Observability)
|
||||
if ok {
|
||||
return obs.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetStatusErrorf flags the span as in error and log an event.
|
||||
func SetStatusErrorf(ctx context.Context, format string, args ...any) {
|
||||
if span := trace.SpanFromContext(ctx); span != nil {
|
||||
|
||||
@ -26,10 +26,6 @@ THE SOFTWARE.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
dynamic "github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
)
|
||||
|
||||
// RouteApplyConfiguration represents a declarative configuration of the Route type for use
|
||||
// with apply.
|
||||
//
|
||||
@ -58,7 +54,7 @@ type RouteApplyConfiguration struct {
|
||||
Middlewares []MiddlewareRefApplyConfiguration `json:"middlewares,omitempty"`
|
||||
// Observability defines the observability configuration for a router.
|
||||
// More info: https://doc.traefik.io/traefik/v3.7/reference/routing-configuration/http/routing/observability/
|
||||
Observability *dynamic.RouterObservabilityConfig `json:"observability,omitempty"`
|
||||
Observability *RouterObservabilityConfigApplyConfiguration `json:"observability,omitempty"`
|
||||
}
|
||||
|
||||
// RouteApplyConfiguration constructs a declarative configuration of the Route type for use with
|
||||
@ -128,7 +124,7 @@ func (b *RouteApplyConfiguration) WithMiddlewares(values ...*MiddlewareRefApplyC
|
||||
// WithObservability sets the Observability field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Observability field is set to the value of the last call.
|
||||
func (b *RouteApplyConfiguration) WithObservability(value dynamic.RouterObservabilityConfig) *RouteApplyConfiguration {
|
||||
b.Observability = &value
|
||||
func (b *RouteApplyConfiguration) WithObservability(value *RouterObservabilityConfigApplyConfiguration) *RouteApplyConfiguration {
|
||||
b.Observability = value
|
||||
return b
|
||||
}
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2020 Containous SAS; 2020-2026 Traefik Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
types "github.com/traefik/traefik/v3/pkg/observability/types"
|
||||
)
|
||||
|
||||
// RouterObservabilityConfigApplyConfiguration represents a declarative configuration of the RouterObservabilityConfig type for use
|
||||
// with apply.
|
||||
//
|
||||
// RouterObservabilityConfig holds the observability configuration for a router.
|
||||
// More info: https://doc.traefik.io/traefik/v3.7/reference/routing-configuration/http/routing/observability/
|
||||
type RouterObservabilityConfigApplyConfiguration struct {
|
||||
// AccessLogs enables access logs for this router.
|
||||
AccessLogs *bool `json:"accessLogs,omitempty"`
|
||||
// Metrics enables metrics for this router.
|
||||
Metrics *bool `json:"metrics,omitempty"`
|
||||
// Tracing enables tracing for this router.
|
||||
Tracing *bool `json:"tracing,omitempty"`
|
||||
// TraceVerbosity defines the verbosity level of the tracing for this router.
|
||||
TraceVerbosity *types.TracingVerbosity `json:"traceVerbosity,omitempty"`
|
||||
}
|
||||
|
||||
// RouterObservabilityConfigApplyConfiguration constructs a declarative configuration of the RouterObservabilityConfig type for use with
|
||||
// apply.
|
||||
func RouterObservabilityConfig() *RouterObservabilityConfigApplyConfiguration {
|
||||
return &RouterObservabilityConfigApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithAccessLogs sets the AccessLogs field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the AccessLogs field is set to the value of the last call.
|
||||
func (b *RouterObservabilityConfigApplyConfiguration) WithAccessLogs(value bool) *RouterObservabilityConfigApplyConfiguration {
|
||||
b.AccessLogs = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithMetrics sets the Metrics field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Metrics field is set to the value of the last call.
|
||||
func (b *RouterObservabilityConfigApplyConfiguration) WithMetrics(value bool) *RouterObservabilityConfigApplyConfiguration {
|
||||
b.Metrics = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithTracing sets the Tracing field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Tracing field is set to the value of the last call.
|
||||
func (b *RouterObservabilityConfigApplyConfiguration) WithTracing(value bool) *RouterObservabilityConfigApplyConfiguration {
|
||||
b.Tracing = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithTraceVerbosity sets the TraceVerbosity field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the TraceVerbosity field is set to the value of the last call.
|
||||
func (b *RouterObservabilityConfigApplyConfiguration) WithTraceVerbosity(value types.TracingVerbosity) *RouterObservabilityConfigApplyConfiguration {
|
||||
b.TraceVerbosity = &value
|
||||
return b
|
||||
}
|
||||
@ -118,6 +118,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return &traefikiov1alpha1.RootCAApplyConfiguration{}
|
||||
case v1alpha1.SchemeGroupVersion.WithKind("Route"):
|
||||
return &traefikiov1alpha1.RouteApplyConfiguration{}
|
||||
case v1alpha1.SchemeGroupVersion.WithKind("RouterObservabilityConfig"):
|
||||
return &traefikiov1alpha1.RouterObservabilityConfigApplyConfiguration{}
|
||||
case v1alpha1.SchemeGroupVersion.WithKind("RouteTCP"):
|
||||
return &traefikiov1alpha1.RouteTCPApplyConfiguration{}
|
||||
case v1alpha1.SchemeGroupVersion.WithKind("RouteUDP"):
|
||||
|
||||
@ -122,14 +122,22 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
|
||||
}
|
||||
|
||||
r := &dynamic.Router{
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
RuleSyntax: route.Syntax,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
Observability: route.Observability,
|
||||
ParentRefs: parentRouterNames,
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
RuleSyntax: route.Syntax,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
ParentRefs: parentRouterNames,
|
||||
}
|
||||
|
||||
if route.Observability != nil {
|
||||
r.Observability = &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: route.Observability.AccessLogs,
|
||||
Metrics: route.Observability.Metrics,
|
||||
Tracing: route.Observability.Tracing,
|
||||
TraceVerbosity: route.Observability.TraceVerbosity,
|
||||
}
|
||||
}
|
||||
|
||||
if ingressRoute.Spec.TLS != nil {
|
||||
|
||||
@ -2,6 +2,7 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
otypes "github.com/traefik/traefik/v3/pkg/observability/types"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
@ -54,7 +55,22 @@ type Route struct {
|
||||
Middlewares []MiddlewareRef `json:"middlewares,omitempty"`
|
||||
// Observability defines the observability configuration for a router.
|
||||
// More info: https://doc.traefik.io/traefik/v3.7/reference/routing-configuration/http/routing/observability/
|
||||
Observability *dynamic.RouterObservabilityConfig `json:"observability,omitempty"`
|
||||
Observability *RouterObservabilityConfig `json:"observability,omitempty"`
|
||||
}
|
||||
|
||||
// RouterObservabilityConfig holds the observability configuration for a router.
|
||||
// More info: https://doc.traefik.io/traefik/v3.7/reference/routing-configuration/http/routing/observability/
|
||||
type RouterObservabilityConfig struct {
|
||||
// AccessLogs enables access logs for this router.
|
||||
AccessLogs *bool `json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"`
|
||||
// Metrics enables metrics for this router.
|
||||
Metrics *bool `json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"`
|
||||
// Tracing enables tracing for this router.
|
||||
Tracing *bool `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"`
|
||||
// TraceVerbosity defines the verbosity level of the tracing for this router.
|
||||
// +kubebuilder:validation:Enum=minimal;detailed
|
||||
// +kubebuilder:default=minimal
|
||||
TraceVerbosity otypes.TracingVerbosity `json:"traceVerbosity,omitempty" toml:"traceVerbosity,omitempty" yaml:"traceVerbosity,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// TLS holds the TLS configuration.
|
||||
|
||||
@ -1382,7 +1382,7 @@ func (in *Route) DeepCopyInto(out *Route) {
|
||||
}
|
||||
if in.Observability != nil {
|
||||
in, out := &in.Observability, &out.Observability
|
||||
*out = new(dynamic.RouterObservabilityConfig)
|
||||
*out = new(RouterObservabilityConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
@ -1449,6 +1449,37 @@ func (in *RouteUDP) DeepCopy() *RouteUDP {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RouterObservabilityConfig) DeepCopyInto(out *RouterObservabilityConfig) {
|
||||
*out = *in
|
||||
if in.AccessLogs != nil {
|
||||
in, out := &in.AccessLogs, &out.AccessLogs
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.Metrics != nil {
|
||||
in, out := &in.Metrics, &out.Metrics
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.Tracing != nil {
|
||||
in, out := &in.Tracing, &out.Tracing
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterObservabilityConfig.
|
||||
func (in *RouterObservabilityConfig) DeepCopy() *RouterObservabilityConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RouterObservabilityConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServerHealthCheck) DeepCopyInto(out *ServerHealthCheck) {
|
||||
*out = *in
|
||||
|
||||
@ -417,24 +417,36 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
return conf
|
||||
}
|
||||
|
||||
obs := &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
// No ingress and no service port with the global default backend.
|
||||
Namespace: p.defaultBackendServiceNamespace,
|
||||
ServiceName: p.defaultBackendServiceName,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Add the default backend service router to the configuration.
|
||||
conf.HTTP.Routers[defaultBackendName] = &dynamic.Router{
|
||||
EntryPoints: p.NonTLSEntryPoints,
|
||||
Rule: `PathPrefix("/")`,
|
||||
// "default" stands for the default rule syntax in Traefik v3, i.e. the v3 syntax.
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: defaultBackendName,
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: defaultBackendName,
|
||||
Observability: obs,
|
||||
}
|
||||
|
||||
conf.HTTP.Routers[defaultBackendTLSName] = &dynamic.Router{
|
||||
EntryPoints: p.TLSEntryPoints,
|
||||
Rule: `PathPrefix("/")`,
|
||||
// "default" stands for the default rule syntax in Traefik v3, i.e. the v3 syntax.
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: defaultBackendName,
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: defaultBackendName,
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: obs,
|
||||
}
|
||||
|
||||
conf.HTTP.Services[defaultBackendName] = svc
|
||||
@ -586,9 +598,10 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
}
|
||||
|
||||
var defaultBackendService *dynamic.Service
|
||||
var defaultBackendObs *dynamic.RouterObservabilityConfig
|
||||
if ingress.Spec.DefaultBackend != nil && ingress.Spec.DefaultBackend.Service != nil {
|
||||
var err error
|
||||
defaultBackendService, err = p.buildService(ingress.Namespace, *ingress.Spec.DefaultBackend, namedServersTransport, ingress.IngressConfig)
|
||||
defaultBackendService, err = p.buildService(ingress.Namespace, *ingress.Spec.DefaultBackend, &namedServersTransport, ingress.IngressConfig)
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
Str("serviceName", ingress.Spec.DefaultBackend.Service.Name).
|
||||
@ -596,6 +609,17 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
Err(err).
|
||||
Msg("Cannot create default backend service")
|
||||
}
|
||||
|
||||
defaultBackendObs = &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: ingress.Namespace,
|
||||
IngressName: ingress.Name,
|
||||
ServiceName: ingress.Spec.DefaultBackend.Service.Name,
|
||||
ServicePort: portString(ingress.Spec.DefaultBackend.Service.Port),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if defaultBackendService != nil && len(ingress.Spec.Rules) == 0 {
|
||||
@ -603,9 +627,10 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
EntryPoints: p.NonTLSEntryPoints,
|
||||
Rule: `PathPrefix("/")`,
|
||||
// "default" stands for the default rule syntax in Traefik v3, i.e. the v3 syntax.
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: defaultBackendName,
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: defaultBackendName,
|
||||
Observability: defaultBackendObs,
|
||||
}
|
||||
|
||||
if err := p.applyMiddlewares(ingress, defaultBackendName, "", "", ingress.Spec.DefaultBackend, hosts, rt, conf, ""); err != nil {
|
||||
@ -624,6 +649,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: clientAuthTLSOptionName,
|
||||
},
|
||||
Observability: defaultBackendObs,
|
||||
}
|
||||
|
||||
if err := p.applyMiddlewares(ingress, defaultBackendTLSName, "", "", ingress.Spec.DefaultBackend, hosts, rtTLS, conf, ""); err != nil {
|
||||
@ -632,10 +658,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
|
||||
conf.HTTP.Routers[defaultBackendTLSName] = rtTLS
|
||||
|
||||
if namedServersTransport != nil && defaultBackendService.LoadBalancer != nil {
|
||||
defaultBackendService.LoadBalancer.ServersTransport = namedServersTransport.Name
|
||||
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
|
||||
}
|
||||
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
|
||||
conf.HTTP.Services[defaultBackendName] = defaultBackendService
|
||||
}
|
||||
|
||||
@ -695,8 +718,9 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
EntryPoints: p.NonTLSEntryPoints,
|
||||
Rule: fmt.Sprintf("Host(%q)", rule.Host),
|
||||
// "default" stands for the default rule syntax in Traefik v3, i.e. the v3 syntax.
|
||||
RuleSyntax: "default",
|
||||
Service: key,
|
||||
RuleSyntax: "default",
|
||||
Service: key,
|
||||
Observability: defaultBackendObs,
|
||||
}
|
||||
|
||||
if err := p.applyMiddlewares(ingress, key, "", "", ingress.Spec.DefaultBackend, hosts, rt, conf, serverSnippets[rule.Host]); err != nil {
|
||||
@ -714,6 +738,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: clientAuthTLSOptionName,
|
||||
},
|
||||
Observability: defaultBackendObs,
|
||||
}
|
||||
|
||||
if err := p.applyMiddlewares(ingress, key+"-tls", "", "", ingress.Spec.DefaultBackend, hosts, rtTLS, conf, serverSnippets[rule.Host]); err != nil {
|
||||
@ -722,11 +747,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
|
||||
conf.HTTP.Routers[key+"-tls"] = rtTLS
|
||||
|
||||
if namedServersTransport != nil && defaultBackendService.LoadBalancer != nil {
|
||||
defaultBackendService.LoadBalancer.ServersTransport = namedServersTransport.Name
|
||||
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
|
||||
}
|
||||
|
||||
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
|
||||
conf.HTTP.Services[key] = defaultBackendService
|
||||
}
|
||||
|
||||
@ -746,9 +767,20 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
continue
|
||||
}
|
||||
|
||||
pathObs := &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: ingress.Namespace,
|
||||
IngressName: ingress.Name,
|
||||
ServiceName: pa.Backend.Service.Name,
|
||||
ServicePort: portString(pa.Backend.Service.Port),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: if no service, do not add middlewares and 503.
|
||||
serviceName := provider.Normalize(ingress.Namespace + "-" + ingress.Name + "-" + pa.Backend.Service.Name + "-" + portString(pa.Backend.Service.Port))
|
||||
service, err := p.buildService(ingress.Namespace, pa.Backend, namedServersTransport, ingress.IngressConfig)
|
||||
service, err := p.buildService(ingress.Namespace, pa.Backend, &namedServersTransport, ingress.IngressConfig)
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
Str("serviceName", pa.Backend.Service.Name).
|
||||
@ -769,7 +801,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
canaryBackend, hasCanaryBackend := canaryBackends[canaryBackendKey(ingress.Namespace, *pa.Backend.Service)]
|
||||
if hasCanaryBackend {
|
||||
canaryServiceName = serviceName + "-canary"
|
||||
canaryService, err = p.buildService(ingress.Namespace, *canaryBackend.IngressBackend, namedServersTransport, ingress.IngressConfig)
|
||||
canaryService, err = p.buildService(ingress.Namespace, *canaryBackend.IngressBackend, &namedServersTransport, ingress.IngressConfig)
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
Str("serviceName", canaryBackend.IngressBackend.Service.Name).
|
||||
@ -795,8 +827,9 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
EntryPoints: p.NonTLSEntryPoints,
|
||||
Rule: buildRule(ctxIngress, rule.Host, pa, ingress.IngressConfig, hosts, hostsWithUseRegex),
|
||||
// "default" stands for the default rule syntax in Traefik v3, i.e. the v3 syntax.
|
||||
RuleSyntax: "default",
|
||||
Service: serviceName,
|
||||
RuleSyntax: "default",
|
||||
Service: serviceName,
|
||||
Observability: pathObs,
|
||||
}
|
||||
|
||||
routerKey := provider.Normalize(fmt.Sprintf("%s-%s-rule-%d-path-%d", ingress.Namespace, ingress.Name, ri, pi))
|
||||
@ -811,6 +844,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: clientAuthTLSOptionName,
|
||||
},
|
||||
Observability: pathObs,
|
||||
}
|
||||
|
||||
routerKeyTLS := routerKey + "-tls"
|
||||
@ -838,11 +872,11 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
if hasCanaryBackend && canaryBackend.RequiresCanaryRouter() {
|
||||
canaryRouterKey := routerKey + "-canary"
|
||||
canaryRouter := &dynamic.Router{
|
||||
EntryPoints: rt.EntryPoints,
|
||||
Rule: canaryBackend.AppendCanaryRule(rt.Rule),
|
||||
RuleSyntax: rt.RuleSyntax,
|
||||
Service: canaryServiceName,
|
||||
TLS: rt.TLS,
|
||||
EntryPoints: rt.EntryPoints,
|
||||
Rule: canaryBackend.AppendCanaryRule(rt.Rule),
|
||||
RuleSyntax: rt.RuleSyntax,
|
||||
Service: canaryServiceName,
|
||||
Observability: pathObs,
|
||||
}
|
||||
conf.HTTP.Routers[canaryRouterKey] = canaryRouter
|
||||
|
||||
@ -853,11 +887,12 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
// default TLS router
|
||||
canaryRouterKeyTLS := canaryRouterKey + "-tls"
|
||||
canaryRouterTLS := &dynamic.Router{
|
||||
EntryPoints: rtTLS.EntryPoints,
|
||||
Rule: canaryBackend.AppendCanaryRule(rtTLS.Rule),
|
||||
RuleSyntax: rtTLS.RuleSyntax,
|
||||
Service: canaryServiceName,
|
||||
TLS: rtTLS.TLS,
|
||||
EntryPoints: rtTLS.EntryPoints,
|
||||
Rule: canaryBackend.AppendCanaryRule(rtTLS.Rule),
|
||||
RuleSyntax: rtTLS.RuleSyntax,
|
||||
Service: canaryServiceName,
|
||||
TLS: rtTLS.TLS,
|
||||
Observability: pathObs,
|
||||
}
|
||||
conf.HTTP.Routers[canaryRouterKeyTLS] = canaryRouterTLS
|
||||
|
||||
@ -869,11 +904,11 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
if hasCanaryBackend && canaryBackend.RequiresNonCanaryRouter() {
|
||||
nonCanaryRouterKey := routerKey + "-non-canary"
|
||||
nonCanaryRouter := &dynamic.Router{
|
||||
EntryPoints: rt.EntryPoints,
|
||||
Rule: canaryBackend.AppendNonCanaryRule(rt.Rule),
|
||||
RuleSyntax: rt.RuleSyntax,
|
||||
Service: serviceName,
|
||||
TLS: rt.TLS,
|
||||
EntryPoints: rt.EntryPoints,
|
||||
Rule: canaryBackend.AppendNonCanaryRule(rt.Rule),
|
||||
RuleSyntax: rt.RuleSyntax,
|
||||
Service: serviceName,
|
||||
Observability: pathObs,
|
||||
}
|
||||
conf.HTTP.Routers[nonCanaryRouterKey] = nonCanaryRouter
|
||||
|
||||
@ -884,11 +919,12 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
// default TLS router
|
||||
nonCanaryRouterKeyTLS := nonCanaryRouterKey + "-tls"
|
||||
nonCanaryRouterTLS := &dynamic.Router{
|
||||
EntryPoints: rtTLS.EntryPoints,
|
||||
Rule: canaryBackend.AppendNonCanaryRule(rtTLS.Rule),
|
||||
RuleSyntax: rtTLS.RuleSyntax,
|
||||
Service: serviceName,
|
||||
TLS: rtTLS.TLS,
|
||||
EntryPoints: rtTLS.EntryPoints,
|
||||
Rule: canaryBackend.AppendNonCanaryRule(rtTLS.Rule),
|
||||
RuleSyntax: rtTLS.RuleSyntax,
|
||||
Service: serviceName,
|
||||
TLS: rtTLS.TLS,
|
||||
Observability: pathObs,
|
||||
}
|
||||
conf.HTTP.Routers[nonCanaryRouterKeyTLS] = nonCanaryRouterTLS
|
||||
|
||||
@ -897,9 +933,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
if namedServersTransport != nil {
|
||||
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
|
||||
}
|
||||
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -945,11 +979,11 @@ func (p *Provider) isIngressValid(ingress ingress) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) buildServersTransport(ctx context.Context, namespace, name string, cfg IngressConfig) (*namedServersTransport, error) {
|
||||
func (p *Provider) buildServersTransport(ctx context.Context, namespace, name string, cfg IngressConfig) (namedServersTransport, error) {
|
||||
proxyConnectTimeout := ptr.Deref(cfg.ProxyConnectTimeout, p.ProxyConnectTimeout)
|
||||
proxyReadTimeout := ptr.Deref(cfg.ProxyReadTimeout, p.ProxyReadTimeout)
|
||||
proxySendTimeout := ptr.Deref(cfg.ProxySendTimeout, p.ProxySendTimeout)
|
||||
nst := &namedServersTransport{
|
||||
nst := namedServersTransport{
|
||||
Name: provider.Normalize(namespace + "-" + name),
|
||||
ServersTransport: &dynamic.ServersTransport{
|
||||
ForwardingTimeouts: &dynamic.ForwardingTimeouts{
|
||||
@ -982,17 +1016,17 @@ func (p *Provider) buildServersTransport(ctx context.Context, namespace, name st
|
||||
if sslSecret := ptr.Deref(cfg.ProxySSLSecret, ""); sslSecret != "" {
|
||||
parts := strings.Split(sslSecret, "/")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("malformed proxy SSL secret: %s, expected namespace/name", sslSecret)
|
||||
return namedServersTransport{}, fmt.Errorf("malformed proxy SSL secret: %s, expected namespace/name", sslSecret)
|
||||
}
|
||||
|
||||
secretNamespace, secretName := parts[0], parts[1]
|
||||
if !p.AllowCrossNamespaceResources && secretNamespace != namespace {
|
||||
return nil, fmt.Errorf("cross-namespace proxy ssl secret is not allowed: secret %s/%s is not from ingress namespace %q", secretName, secretNamespace, namespace)
|
||||
return namedServersTransport{}, fmt.Errorf("cross-namespace proxy ssl secret is not allowed: secret %s/%s is not from ingress namespace %q", secretName, secretNamespace, namespace)
|
||||
}
|
||||
|
||||
blocks, err := p.certificateBlocks(secretNamespace, secretName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting certificate blocks: %w", err)
|
||||
return namedServersTransport{}, fmt.Errorf("getting certificate blocks: %w", err)
|
||||
}
|
||||
|
||||
if blocks.CA != nil {
|
||||
@ -1299,7 +1333,7 @@ func (p *Provider) applyMiddlewares(ingress ingress, routerKey, rulePath, ruleHo
|
||||
return fmt.Errorf("applying custom HTTP errors: %w", err)
|
||||
}
|
||||
applyAppRootConfiguration(routerKey, ingress.IngressConfig, rt, conf)
|
||||
applyFromToWwwRedirect(hosts, ruleHost, routerKey, ingress.IngressConfig, rt, conf)
|
||||
applyFromToWwwRedirect(hosts, ruleHost, routerKey, ingress, backend, rt, conf)
|
||||
applyRedirect(routerKey, ingress.IngressConfig, rt, conf)
|
||||
|
||||
if err := p.applyBasicAuthConfiguration(ingress.Namespace, routerKey, ingress.IngressConfig, rt, conf); err != nil {
|
||||
@ -1645,8 +1679,8 @@ func applyAppRootConfiguration(routerName string, ingressConfig IngressConfig, r
|
||||
rt.Middlewares = append(rt.Middlewares, appRootMiddlewareName)
|
||||
}
|
||||
|
||||
func applyFromToWwwRedirect(hosts map[string]bool, ruleHost, routerName string, ingressConfig IngressConfig, rt *dynamic.Router, conf *dynamic.Configuration) {
|
||||
if ingressConfig.FromToWwwRedirect == nil || !*ingressConfig.FromToWwwRedirect {
|
||||
func applyFromToWwwRedirect(hosts map[string]bool, ruleHost, routerName string, ingress ingress, backend *netv1.IngressBackend, rt *dynamic.Router, conf *dynamic.Configuration) {
|
||||
if ingress.IngressConfig.FromToWwwRedirect == nil || !*ingress.IngressConfig.FromToWwwRedirect {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1676,6 +1710,16 @@ func applyFromToWwwRedirect(hosts map[string]bool, ruleHost, routerName string,
|
||||
},
|
||||
}
|
||||
|
||||
ingressMetadata := &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: ingress.Namespace,
|
||||
IngressName: ingress.Name,
|
||||
}
|
||||
|
||||
if backend != nil && backend.Service != nil {
|
||||
ingressMetadata.ServiceName = backend.Service.Name
|
||||
ingressMetadata.ServicePort = portString(backend.Service.Port)
|
||||
}
|
||||
|
||||
wwwRedirectRouter := &dynamic.Router{
|
||||
EntryPoints: rt.EntryPoints,
|
||||
Rule: newRule,
|
||||
@ -1685,6 +1729,11 @@ func applyFromToWwwRedirect(hosts map[string]bool, ruleHost, routerName string,
|
||||
Middlewares: []string{fromToWwwRedirectMiddlewareName},
|
||||
Service: rt.Service,
|
||||
TLS: rt.TLS,
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: ingressMetadata,
|
||||
},
|
||||
},
|
||||
}
|
||||
conf.HTTP.Routers[routerName+"-from-to-www-redirect"] = wwwRedirectRouter
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -306,13 +306,29 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: "default-backend",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: ingress.Namespace,
|
||||
IngressName: ingress.Name,
|
||||
ServiceName: ingress.Spec.DefaultBackend.Service.Name,
|
||||
ServicePort: portString(ingress.Spec.DefaultBackend.Service.Port),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if rtConfig != nil && rtConfig.Router != nil {
|
||||
rt.EntryPoints = rtConfig.Router.EntryPoints
|
||||
rt.Middlewares = rtConfig.Router.Middlewares
|
||||
rt.TLS = rtConfig.Router.TLS
|
||||
rt.Observability = rtConfig.Router.Observability
|
||||
|
||||
if rtConfig.Router.Observability != nil {
|
||||
rt.Observability.AccessLogs = rtConfig.Router.Observability.AccessLogs
|
||||
rt.Observability.Metrics = rtConfig.Router.Observability.Metrics
|
||||
rt.Observability.Tracing = rtConfig.Router.Observability.Tracing
|
||||
rt.Observability.TraceVerbosity = rtConfig.Router.Observability.TraceVerbosity
|
||||
}
|
||||
}
|
||||
|
||||
p.applyRouterTransform(ctxIngress, rt, ingress)
|
||||
@ -358,16 +374,10 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
||||
continue
|
||||
}
|
||||
|
||||
portString := pa.Backend.Service.Port.Name
|
||||
|
||||
if len(pa.Backend.Service.Port.Name) == 0 {
|
||||
portString = strconv.Itoa(int(pa.Backend.Service.Port.Number))
|
||||
}
|
||||
|
||||
serviceName := provider.Normalize(ingress.Namespace + "-" + pa.Backend.Service.Name + "-" + portString)
|
||||
serviceName := provider.Normalize(ingress.Namespace + "-" + pa.Backend.Service.Name + "-" + portString(pa.Backend.Service.Port))
|
||||
conf.HTTP.Services[serviceName] = service
|
||||
|
||||
rt := p.loadRouter(rule, pa, rtConfig, serviceName)
|
||||
rt := p.loadRouter(ingress, rule, pa, rtConfig, serviceName)
|
||||
|
||||
p.applyRouterTransform(ctxIngress, rt, ingress)
|
||||
|
||||
@ -689,9 +699,19 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router {
|
||||
func (p *Provider) loadRouter(ingress *netv1.Ingress, rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router {
|
||||
rt := &dynamic.Router{
|
||||
Service: serviceName,
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: ingress.Namespace,
|
||||
IngressName: ingress.Name,
|
||||
ServiceName: pa.Backend.Service.Name,
|
||||
ServicePort: portString(pa.Backend.Service.Port),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if rtConfig != nil && rtConfig.Router != nil {
|
||||
@ -700,7 +720,13 @@ func (p *Provider) loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath,
|
||||
rt.EntryPoints = rtConfig.Router.EntryPoints
|
||||
rt.Middlewares = rtConfig.Router.Middlewares
|
||||
rt.TLS = rtConfig.Router.TLS
|
||||
rt.Observability = rtConfig.Router.Observability
|
||||
|
||||
if rtConfig.Router.Observability != nil {
|
||||
rt.Observability.AccessLogs = rtConfig.Router.Observability.AccessLogs
|
||||
rt.Observability.Metrics = rtConfig.Router.Observability.Metrics
|
||||
rt.Observability.Tracing = rtConfig.Router.Observability.Tracing
|
||||
rt.Observability.TraceVerbosity = rtConfig.Router.Observability.TraceVerbosity
|
||||
}
|
||||
}
|
||||
|
||||
var rules []string
|
||||
@ -928,3 +954,10 @@ func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *s
|
||||
|
||||
return eventsChanBuffered
|
||||
}
|
||||
|
||||
func portString(port netv1.ServiceBackendPort) string {
|
||||
if port.Name == "" {
|
||||
return strconv.Itoa(int(port.Number))
|
||||
}
|
||||
return port.Name
|
||||
}
|
||||
|
||||
@ -73,6 +73,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -129,6 +138,13 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
Tracing: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -172,10 +188,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-foo": {
|
||||
Rule: `PathPrefix("/foo")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -209,10 +243,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar-bar-41871576e140babe40bd": {
|
||||
Rule: `Host("*.bar") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-bar-bar-605945111a3c9f84dc65": {
|
||||
Rule: `Host("bar") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -246,10 +298,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-foo-bar-930f0e8b221e60bc7ab7": {
|
||||
Rule: `PathPrefix("/foo/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-foo-bar-207cc2245cb31ba18e29": {
|
||||
Rule: `PathPrefix("/foo-bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -283,10 +353,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-foo": {
|
||||
Rule: `PathPrefix("/foo")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -320,6 +408,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -353,6 +450,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-example-com": {
|
||||
Rule: `Host("example.com")`,
|
||||
Service: "testing-example-com-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "example-com",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -383,10 +489,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-traefik-tchouk-foo": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/foo")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -420,10 +544,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-traefik-courgette-carotte": {
|
||||
Rule: `Host("traefik.courgette") && PathPrefix("/carotte")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -457,10 +599,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-traefik-courgette-carotte": {
|
||||
Rule: `Host("traefik.courgette") && PathPrefix("/carotte")`,
|
||||
Service: "testing-service2-8082",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service2",
|
||||
ServicePort: "8082",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -512,6 +672,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -591,6 +760,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
RuleSyntax: "default",
|
||||
Service: "default-backend",
|
||||
Priority: math.MinInt32,
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -624,6 +802,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -657,6 +844,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-tchouk",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "tchouk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -690,6 +886,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-tchouk",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "tchouk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -723,10 +928,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-tchouk",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "tchouk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-traefik-tchouk-foo": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/foo")`,
|
||||
Service: "testing-service1-carotte",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "carotte",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -777,6 +1000,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-tchouk",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "tchouk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -810,10 +1042,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-tchouk",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "tchouk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"toto-toto-traefik-tchouk-bar": {
|
||||
Rule: `Host("toto.traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "toto-service1-tchouk",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "toto",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "tchouk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -884,6 +1134,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-traefik-port-port": {
|
||||
Rule: `Host("traefik.port") && PathPrefix("/port")`,
|
||||
Service: "testing-service1-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -914,7 +1173,16 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-example-com": {
|
||||
Rule: `Host("example.com")`,
|
||||
Service: "testing-example-com-80",
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "example-com",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -955,6 +1223,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-443",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "443",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -988,6 +1265,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-8443",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8443",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1022,6 +1308,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-8443",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8443",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1057,6 +1352,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
RuleSyntax: "default",
|
||||
Service: "default-backend",
|
||||
Priority: math.MinInt32,
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1090,6 +1394,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1163,6 +1476,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-foobar-com-bar": {
|
||||
Rule: `Host("*.foobar.com") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1196,6 +1518,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-foobar-com-bar": {
|
||||
Rule: `HostRegexp("{subdomain:[a-zA-Z0-9-]+}.foobar.com") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1228,10 +1559,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-foo": {
|
||||
Rule: `PathPrefix("/foo")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1263,6 +1612,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-foo": {
|
||||
Rule: `PathPrefix("/foo")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1293,6 +1651,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1323,6 +1690,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `Path("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1353,6 +1729,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `Path("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1383,6 +1768,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `Path("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1413,6 +1807,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1446,6 +1849,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1479,6 +1891,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1509,6 +1930,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1565,6 +1995,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-foobar",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "foobar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1607,6 +2046,16 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
RuleSyntax: "default",
|
||||
Priority: math.MinInt32,
|
||||
Service: "default-backend",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
IngressName: "defaultbackend",
|
||||
ServiceName: "defaultservice",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1637,6 +2086,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1678,6 +2136,15 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||
"testing-bar": {
|
||||
Rule: `(Path("/bar") || PathPrefix("/bar/"))`,
|
||||
Service: "testing-service1-80",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1752,6 +2219,15 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1782,6 +2258,16 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
|
||||
"testing-example-com-bar": {
|
||||
Rule: `PathPrefix("/bar")`,
|
||||
Service: "testing-service-bar-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
IngressName: "example.com",
|
||||
ServiceName: "service-bar",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1813,6 +2299,16 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
|
||||
"testing-example-com-foo": {
|
||||
Rule: `PathPrefix("/foo")`,
|
||||
Service: "testing-service-foo-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
IngressName: "example.com",
|
||||
ServiceName: "service-foo",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1866,6 +2362,15 @@ func TestLoadConfigurationFromIngressesWithNativeLB(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -1916,6 +2421,15 @@ func TestLoadConfigurationFromIngressesWithNodePortLB(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -2154,6 +2668,15 @@ func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
|
||||
"testing-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "testing-service1-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "testing",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -2182,6 +2705,16 @@ func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
|
||||
"default-global-native-lb-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "default-service1-8080",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "default",
|
||||
IngressName: "global-native-lb",
|
||||
ServiceName: "service1",
|
||||
ServicePort: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
@ -2210,6 +2743,16 @@ func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
|
||||
"default-global-native-lb-traefik-tchouk-bar": {
|
||||
Rule: `Host("traefik.tchouk") && PathPrefix("/bar")`,
|
||||
Service: "default-native-disabled-svc-web",
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
Metadata: &dynamic.ObservabilityMetadata{
|
||||
Ingress: &dynamic.KubernetesIngressMetadata{
|
||||
Namespace: "default",
|
||||
IngressName: "global-native-lb",
|
||||
ServiceName: "native-disabled-svc",
|
||||
ServicePort: "web",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
|
||||
@ -132,6 +132,7 @@ func (o *ObservabilityMgr) observabilityContextHandler(next http.Handler, intern
|
||||
SemConvMetricsEnabled: o.shouldMeterSemConv(internal, config),
|
||||
TracingEnabled: o.shouldTrace(internal, config, otypes.MinimalVerbosity),
|
||||
DetailedTracingEnabled: o.shouldTrace(internal, config, otypes.DetailedVerbosity),
|
||||
Metadata: config.Metadata,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user