Fix HTTP challenge router unexpected delayed creation
This commit is contained in:
parent
9a931e4dc9
commit
2065f4c003
4 changed files with 98 additions and 8 deletions
|
@ -1,7 +1,7 @@
|
|||
whoami:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.http.routers.route1.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.route1.rule=PathPrefix(`/foo`)
|
||||
- traefik.http.routers.route1.middlewares=passtls
|
||||
- traefik.http.routers.route1.tls=true
|
||||
- traefik.http.middlewares.passtls.passtlsclientcert.pem=true
|
||||
|
|
|
@ -50,10 +50,10 @@ func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("PathPrefix(`/`)"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("PathPrefix(`/foo`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8443", nil)
|
||||
request, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8443/foo", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
certificate, err := tls.LoadX509KeyPair(certPemPath, certKeyPath)
|
||||
|
|
|
@ -8,12 +8,14 @@ import (
|
|||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
"github.com/traefik/traefik/v2/pkg/provider"
|
||||
"github.com/traefik/traefik/v2/pkg/provider/file"
|
||||
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
||||
"github.com/traefik/traefik/v2/pkg/safe"
|
||||
)
|
||||
|
||||
// ProviderAggregator aggregates providers.
|
||||
type ProviderAggregator struct {
|
||||
fileProvider *file.Provider
|
||||
internalProvider provider.Provider
|
||||
fileProvider provider.Provider
|
||||
providers []provider.Provider
|
||||
}
|
||||
|
||||
|
@ -98,11 +100,15 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if fileProvider, ok := provider.(*file.Provider); ok {
|
||||
p.fileProvider = fileProvider
|
||||
} else {
|
||||
switch provider.(type) {
|
||||
case *file.Provider:
|
||||
p.fileProvider = provider
|
||||
case *traefik.Provider:
|
||||
p.internalProvider = provider
|
||||
default:
|
||||
p.providers = append(p.providers, provider)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -117,12 +123,17 @@ func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, po
|
|||
launchProvider(configurationChan, pool, p.fileProvider)
|
||||
}
|
||||
|
||||
if p.internalProvider != nil {
|
||||
launchProvider(configurationChan, pool, p.internalProvider)
|
||||
}
|
||||
|
||||
for _, prd := range p.providers {
|
||||
prd := prd
|
||||
safe.Go(func() {
|
||||
launchProvider(configurationChan, pool, prd)
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
79
pkg/provider/aggregator/aggregator_test.go
Normal file
79
pkg/provider/aggregator/aggregator_test.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package aggregator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/provider"
|
||||
"github.com/traefik/traefik/v2/pkg/safe"
|
||||
)
|
||||
|
||||
func TestProviderAggregator_Provide(t *testing.T) {
|
||||
aggregator := ProviderAggregator{
|
||||
internalProvider: &providerMock{"internal"},
|
||||
fileProvider: &providerMock{"file"},
|
||||
providers: []provider.Provider{
|
||||
&providerMock{"salad"},
|
||||
&providerMock{"tomato"},
|
||||
&providerMock{"onion"},
|
||||
},
|
||||
}
|
||||
|
||||
cfgCh := make(chan dynamic.Message)
|
||||
errCh := make(chan error)
|
||||
pool := safe.NewPool(context.Background())
|
||||
|
||||
t.Cleanup(pool.Stop)
|
||||
|
||||
go func() {
|
||||
errCh <- aggregator.Provide(cfgCh, pool)
|
||||
}()
|
||||
|
||||
// Make sure the file provider is always called first, followed by the internal provider.
|
||||
requireReceivedMessageFromProviders(t, cfgCh, []string{"file"})
|
||||
requireReceivedMessageFromProviders(t, cfgCh, []string{"internal"})
|
||||
|
||||
// Check if all providers have been called, the order doesn't matter.
|
||||
requireReceivedMessageFromProviders(t, cfgCh, []string{"salad", "tomato", "onion"})
|
||||
|
||||
require.NoError(t, <-errCh)
|
||||
}
|
||||
|
||||
// requireReceivedMessageFromProviders makes sure the given providers have emitted a message on the given message channel.
|
||||
// Providers order is not enforced.
|
||||
func requireReceivedMessageFromProviders(t *testing.T, cfgCh <-chan dynamic.Message, names []string) {
|
||||
t.Helper()
|
||||
|
||||
var msg dynamic.Message
|
||||
var receivedMessagesFrom []string
|
||||
|
||||
for range names {
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case msg = <-cfgCh:
|
||||
receivedMessagesFrom = append(receivedMessagesFrom, msg.ProviderName)
|
||||
}
|
||||
}
|
||||
|
||||
require.ElementsMatch(t, names, receivedMessagesFrom)
|
||||
}
|
||||
|
||||
type providerMock struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (p *providerMock) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *providerMock) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
|
||||
configurationChan <- dynamic.Message{
|
||||
ProviderName: p.Name,
|
||||
Configuration: &dynamic.Configuration{},
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue