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 {
|
||||
rts := make(map[string]*dynamic.Router)
|
||||
|
||||
modelRouterNames := make(map[string][]string)
|
||||
for name, rt := range cfg.HTTP.Routers {
|
||||
// Only root routers can have models applied.
|
||||
if rt.ParentRefs != nil {
|
||||
rts[name] = rt
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +235,9 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
|||
rtName := name
|
||||
if len(eps) > 1 {
|
||||
rtName = epName + "-" + name
|
||||
modelRouterNames[name] = append(modelRouterNames[name], rtName)
|
||||
}
|
||||
|
||||
rts[rtName] = cp
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue