Fix multi-layer routing with models
This commit is contained in:
parent
a01c73d506
commit
d271750062
2 changed files with 432 additions and 0 deletions
|
|
@ -175,9 +175,11 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
if cfg.HTTP != nil && len(cfg.HTTP.Models) > 0 {
|
if cfg.HTTP != nil && len(cfg.HTTP.Models) > 0 {
|
||||||
rts := make(map[string]*dynamic.Router)
|
rts := make(map[string]*dynamic.Router)
|
||||||
|
|
||||||
|
modelRouterNames := make(map[string][]string)
|
||||||
for name, rt := range cfg.HTTP.Routers {
|
for name, rt := range cfg.HTTP.Routers {
|
||||||
// Only root routers can have models applied.
|
// Only root routers can have models applied.
|
||||||
if rt.ParentRefs != nil {
|
if rt.ParentRefs != nil {
|
||||||
|
rts[name] = rt
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +235,9 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
rtName := name
|
rtName := name
|
||||||
if len(eps) > 1 {
|
if len(eps) > 1 {
|
||||||
rtName = epName + "-" + name
|
rtName = epName + "-" + name
|
||||||
|
modelRouterNames[name] = append(modelRouterNames[name], rtName)
|
||||||
}
|
}
|
||||||
|
|
||||||
rts[rtName] = cp
|
rts[rtName] = cp
|
||||||
} else {
|
} else {
|
||||||
router.EntryPoints = append(router.EntryPoints, epName)
|
router.EntryPoints = append(router.EntryPoints, epName)
|
||||||
|
|
@ -243,6 +247,26 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, rt := range rts {
|
||||||
|
if rt.ParentRefs == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentRefs []string
|
||||||
|
for _, ref := range rt.ParentRefs {
|
||||||
|
// Only add the initial parent ref if it still exists.
|
||||||
|
if _, ok := rts[ref]; ok {
|
||||||
|
parentRefs = append(parentRefs, ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
if names, ok := modelRouterNames[ref]; ok {
|
||||||
|
parentRefs = append(parentRefs, names...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.ParentRefs = parentRefs
|
||||||
|
}
|
||||||
|
|
||||||
cfg.HTTP.Routers = rts
|
cfg.HTTP.Routers = rts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -810,6 +810,414 @@ func Test_applyModel(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "child router with parentRefs, parent not split",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "child router with parentRefs, parent split by model",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"websecure", "web"},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"websecure-parent": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent", "websecure-parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "multiple child routers with parentRefs, parent split by model",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"websecure", "web"},
|
||||||
|
},
|
||||||
|
"child1": {
|
||||||
|
ParentRefs: []string{"parent"},
|
||||||
|
},
|
||||||
|
"child2": {
|
||||||
|
ParentRefs: []string{"parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"auth"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"websecure-parent": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
Middlewares: []string{"auth"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"child1": {
|
||||||
|
ParentRefs: []string{"parent", "websecure-parent"},
|
||||||
|
},
|
||||||
|
"child2": {
|
||||||
|
ParentRefs: []string{"parent", "websecure-parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"auth"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "child router with parentRefs to non-existing parent",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"nonexistent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"nonexistent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "child router with multiple parentRefs, some split",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent1": {
|
||||||
|
EntryPoints: []string{"websecure", "web"},
|
||||||
|
},
|
||||||
|
"parent2": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent1", "parent2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent1": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"websecure-parent1": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"parent2": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent1", "websecure-parent1", "parent2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "child router with multiple parentRefs, all split",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent1": {
|
||||||
|
EntryPoints: []string{"websecure", "web"},
|
||||||
|
},
|
||||||
|
"parent2": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent1", "parent2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"web@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
"websecure@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"web-parent1": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"websecure-parent1": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"parent2": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"websecure-parent1", "web-parent1", "parent2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"web@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
"websecure@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "child router with parentRefs, parent split into three routers",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"websecure", "web", "admin"},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
"admin@internal": {
|
||||||
|
Middlewares: []string{"admin-auth"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"parent": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"websecure-parent": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"admin-parent": {
|
||||||
|
EntryPoints: []string{"admin"},
|
||||||
|
Middlewares: []string{"admin-auth"},
|
||||||
|
Observability: &dynamic.RouterObservabilityConfig{
|
||||||
|
AccessLogs: pointer(true),
|
||||||
|
Metrics: pointer(true),
|
||||||
|
Tracing: pointer(true),
|
||||||
|
TraceVerbosity: otypes.MinimalVerbosity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"child": {
|
||||||
|
ParentRefs: []string{"parent", "websecure-parent", "admin-parent"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
"admin@internal": {
|
||||||
|
Middlewares: []string{"admin-auth"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue