mirror of
https://github.com/traefik/traefik.git
synced 2026-05-05 04:16:25 +02:00
Preserve health check status updater when service has middlewares
This commit is contained in:
parent
86db5c2777
commit
6c7c056b28
@ -189,12 +189,16 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.H
|
||||
return nil, errors.New("chain builder not defined")
|
||||
}
|
||||
chain := m.middlewareChainBuilder.BuildMiddlewareChain(ctx, conf.Middlewares)
|
||||
originalLB := lb
|
||||
var err error
|
||||
lb, err = chain.Then(lb)
|
||||
if err != nil {
|
||||
conf.AddError(err, true)
|
||||
return nil, err
|
||||
}
|
||||
if su, ok := originalLB.(healthcheck.StatusUpdater); ok {
|
||||
lb = &statusUpdaterHandler{Handler: lb, statusUpdater: su}
|
||||
}
|
||||
}
|
||||
|
||||
m.services[serviceName] = lb
|
||||
@ -537,6 +541,18 @@ type serverBalancer interface {
|
||||
AddServer(name string, handler http.Handler, server dynamic.Server)
|
||||
}
|
||||
|
||||
// statusUpdaterHandler wraps an http.Handler while preserving the
|
||||
// healthcheck.StatusUpdater interface from the original handler.
|
||||
type statusUpdaterHandler struct {
|
||||
http.Handler
|
||||
|
||||
statusUpdater healthcheck.StatusUpdater
|
||||
}
|
||||
|
||||
func (s *statusUpdaterHandler) RegisterStatusUpdater(fn func(up bool)) error {
|
||||
return s.statusUpdater.RegisterStatusUpdater(fn)
|
||||
}
|
||||
|
||||
func shuffle[T any](values []T, r *rand.Rand) []T {
|
||||
shuffled := make([]T, len(values))
|
||||
copy(shuffled, values)
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
@ -729,6 +730,77 @@ func (s serviceBuilderFunc) BuildHTTP(ctx context.Context, serviceName string) (
|
||||
return s(ctx, serviceName)
|
||||
}
|
||||
|
||||
func TestGetServiceHandler_HealthCheck(t *testing.T) {
|
||||
pb := httputil.NewProxyBuilder(&transportManagerMock{}, nil)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
withMiddleware bool
|
||||
}{
|
||||
{
|
||||
desc: "without service middleware",
|
||||
},
|
||||
{
|
||||
desc: "with service middleware",
|
||||
withMiddleware: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
t.Cleanup(backend.Close)
|
||||
|
||||
childSvc := &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{{URL: backend.URL}},
|
||||
HealthCheck: &dynamic.ServerHealthCheck{
|
||||
Path: "/health",
|
||||
},
|
||||
},
|
||||
}
|
||||
if test.withMiddleware {
|
||||
childSvc.Middlewares = []string{"add-header@file"}
|
||||
}
|
||||
|
||||
configs := map[string]*runtime.ServiceInfo{
|
||||
"child@file": {Service: childSvc},
|
||||
"wrr@file": {
|
||||
Service: &dynamic.Service{
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{{Name: "child@file", Weight: pointer(1)}},
|
||||
HealthCheck: &dynamic.HealthCheck{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
manager := NewManager(configs, nil, nil, &transportManagerMock{}, pb)
|
||||
if test.withMiddleware {
|
||||
manager.SetMiddlewareChainBuilder(&noopMiddlewareChainBuilder{})
|
||||
}
|
||||
|
||||
_, err := manager.BuildHTTP(t.Context(), "wrr@file")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// noopMiddlewareChainBuilder wraps a handler in a plain http.HandlerFunc,
|
||||
// simulating the effect of service-level middlewares without needing real middleware config.
|
||||
type noopMiddlewareChainBuilder struct{}
|
||||
|
||||
func (n *noopMiddlewareChainBuilder) BuildMiddlewareChain(_ context.Context, _ []string) *alice.Chain {
|
||||
chain := alice.New(func(next http.Handler) (http.Handler, error) {
|
||||
return http.HandlerFunc(next.ServeHTTP), nil
|
||||
})
|
||||
return &chain
|
||||
}
|
||||
|
||||
type internalHandler struct{}
|
||||
|
||||
func (internalHandler) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user