Upgrade golangci-lint

This commit is contained in:
Michael
2026-01-14 17:26:08 +01:00
committed by GitHub
parent 9e5d4ba5a1
commit 51343bc15f
171 changed files with 1463 additions and 1416 deletions
+1 -4
View File
@@ -72,10 +72,7 @@ func pagination(request *http.Request, maximum int) (pageInfo, error) {
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
}
endIndex := startIndex + perPage
if endIndex >= maximum {
endIndex = maximum
}
endIndex := min(startIndex+perPage, maximum)
nextPage := 1
if page*perPage < maximum {
+1 -1
View File
@@ -15,7 +15,7 @@ func init() {
expvar.Publish("Goroutines2", expvar.Func(goroutines))
}
func goroutines() interface{} {
func goroutines() any {
return runtime.NumGoroutine()
}
+3 -2
View File
@@ -30,6 +30,7 @@ func writeError(rw http.ResponseWriter, msg string, code int) {
type serviceInfoRepresentation struct {
*runtime.ServiceInfo
ServerStatus map[string]string `json:"serverStatus,omitempty"`
}
@@ -147,12 +148,12 @@ func getProviderName(id string) string {
return strings.SplitN(id, "@", 2)[1]
}
func extractType(element interface{}) string {
func extractType(element any) string {
v := reflect.ValueOf(element).Elem()
for i := range v.NumField() {
field := v.Field(i)
if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeOf(dynamic.PluginConf{}) {
if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeFor[dynamic.PluginConf]() {
if keys := field.MapKeys(); len(keys) == 1 {
return keys[0].String()
}
+1
View File
@@ -15,6 +15,7 @@ import (
type entryPointRepresentation struct {
*static.EntryPoint
Name string `json:"name,omitempty"`
}
+1 -1
View File
@@ -235,7 +235,7 @@ func TestHandler_EntryPoints(t *testing.T) {
require.NoError(t, err)
if *updateExpected {
var results interface{}
var results any
err := json.Unmarshal(contents, &results)
require.NoError(t, err)
+3
View File
@@ -17,6 +17,7 @@ import (
type routerRepresentation struct {
*runtime.RouterInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
}
@@ -35,6 +36,7 @@ func newRouterRepresentation(name string, rt *runtime.RouterInfo) routerRepresen
type serviceRepresentation struct {
*runtime.ServiceInfo
ServerStatus map[string]string `json:"serverStatus,omitempty"`
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
@@ -53,6 +55,7 @@ func newServiceRepresentation(name string, si *runtime.ServiceInfo) serviceRepre
type middlewareRepresentation struct {
*runtime.MiddlewareInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
Type string `json:"type,omitempty"`
+1 -1
View File
@@ -950,7 +950,7 @@ func TestHandler_HTTP(t *testing.T) {
require.NoError(t, err)
if *updateExpected {
var results interface{}
var results any
err := json.Unmarshal(contents, &results)
require.NoError(t, err)
+1 -1
View File
@@ -232,7 +232,7 @@ func getProviders(conf static.Configuration) []string {
if !field.IsNil() {
providers = append(providers, v.Type().Field(i).Name)
}
} else if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeOf(static.PluginConf{}) {
} else if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeFor[static.PluginConf]() {
for _, value := range field.MapKeys() {
providers = append(providers, "plugin-"+value.String())
}
+2 -2
View File
@@ -243,7 +243,7 @@ func TestHandler_Overview(t *testing.T) {
Rest: &rest.Provider{},
Rancher: &rancher.Provider{},
Plugin: map[string]static.PluginConf{
"test": map[string]interface{}{},
"test": map[string]any{},
},
},
},
@@ -298,7 +298,7 @@ func TestHandler_Overview(t *testing.T) {
require.NoError(t, err)
if *updateExpected {
var results interface{}
var results any
err := json.Unmarshal(contents, &results)
require.NoError(t, err)
+3
View File
@@ -16,6 +16,7 @@ import (
type tcpRouterRepresentation struct {
*runtime.TCPRouterInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
}
@@ -30,6 +31,7 @@ func newTCPRouterRepresentation(name string, rt *runtime.TCPRouterInfo) tcpRoute
type tcpServiceRepresentation struct {
*runtime.TCPServiceInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
Type string `json:"type,omitempty"`
@@ -46,6 +48,7 @@ func newTCPServiceRepresentation(name string, si *runtime.TCPServiceInfo) tcpSer
type tcpMiddlewareRepresentation struct {
*runtime.TCPMiddlewareInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
Type string `json:"type,omitempty"`
+1 -1
View File
@@ -821,7 +821,7 @@ func TestHandler_TCP(t *testing.T) {
require.NoError(t, err)
if *updateExpected {
var results interface{}
var results any
err := json.Unmarshal(contents, &results)
require.NoError(t, err)
+1 -1
View File
@@ -178,7 +178,7 @@ func TestHandler_GetMiddleware(t *testing.T) {
middlewareName string
conf runtime.Configuration
expectedStatus int
expected interface{}
expected any
}{
{
desc: "Middleware not found",
+2
View File
@@ -16,6 +16,7 @@ import (
type udpRouterRepresentation struct {
*runtime.UDPRouterInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
}
@@ -30,6 +31,7 @@ func newUDPRouterRepresentation(name string, rt *runtime.UDPRouterInfo) udpRoute
type udpServiceRepresentation struct {
*runtime.UDPServiceInfo
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
Type string `json:"type,omitempty"`
+1 -1
View File
@@ -560,7 +560,7 @@ func TestHandler_UDP(t *testing.T) {
require.NoError(t, err)
if *updateExpected {
var results interface{}
var results any
err := json.Unmarshal(contents, &results)
require.NoError(t, err)
+1 -1
View File
@@ -63,7 +63,7 @@ func (f *FileLoader) Load(args []string, cmd *cli.Command) (bool, error) {
// loadConfigFiles tries to decode the given configuration file and all default locations for the configuration file.
// It stops as soon as decoding one of them is successful.
func loadConfigFiles(configFile string, element interface{}) (string, error) {
func loadConfigFiles(configFile string, element any) (string, error) {
finder := cli.Finder{
BasePaths: []string{"/etc/traefik/traefik", "$XDG_CONFIG_HOME/traefik", "$HOME/.config/traefik", "./traefik"},
Extensions: []string{"toml", "yaml", "yml"},
+3 -3
View File
@@ -18,7 +18,7 @@ const (
)
// Hydrate hydrates a configuration.
func Hydrate(element interface{}) error {
func Hydrate(element any) error {
field := reflect.ValueOf(element)
return fill(field)
}
@@ -55,7 +55,7 @@ func fill(field reflect.Value) error {
setTyped(field, int32(defaultNumber))
case reflect.Int64:
switch field.Type() {
case reflect.TypeOf(types.Duration(time.Second)):
case reflect.TypeFor[types.Duration]():
setTyped(field, types.Duration(defaultNumber*time.Second))
default:
setTyped(field, int64(defaultNumber))
@@ -81,7 +81,7 @@ func fill(field reflect.Value) error {
return nil
}
func setTyped(field reflect.Value, i interface{}) {
func setTyped(field reflect.Value, i any) {
baseValue := reflect.ValueOf(i)
if field.Kind().String() == field.Type().String() {
field.Set(baseValue)
+2 -2
View File
@@ -21,7 +21,7 @@ func TestDeepCopy(t *testing.T) {
cfgDeepCopy := cfg.DeepCopy()
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg))
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg)) //nolint:modernize // Comparing runtime types of two values.
assert.Equal(t, cfgDeepCopy, cfg)
// Update cfg
@@ -32,6 +32,6 @@ func TestDeepCopy(t *testing.T) {
assert.Equal(t, cfgCopy, cfg)
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg))
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg)) //nolint:modernize // Comparing runtime types of two values.
assert.NotEqual(t, cfgDeepCopy, cfg)
}
+1
View File
@@ -389,6 +389,7 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
// IPWhiteList holds the IP whitelist middleware configuration.
// This middleware limits allowed requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
//
// Deprecated: please use IPAllowList instead.
type IPWhiteList struct {
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). Required.
+3 -3
View File
@@ -44,11 +44,11 @@ func TestPluginConf_DeepCopy_mapOfStruct(t *testing.T) {
}
func TestPluginConf_DeepCopy_map(t *testing.T) {
m := map[string]interface{}{
m := map[string]any{
"name": "bar",
}
p := PluginConf{
"config": map[string]interface{}{
"config": map[string]any{
"foo": m,
},
}
@@ -64,7 +64,7 @@ func TestPluginConf_DeepCopy_map(t *testing.T) {
func TestPluginConf_DeepCopy_panic(t *testing.T) {
p := &PluginConf{
"config": map[string]interface{}{
"config": map[string]any{
"foo": &Foo{Name: "gigi"},
},
}
+1
View File
@@ -26,6 +26,7 @@ type TCPInFlightConn struct {
// TCPIPWhiteList holds the TCP IPWhiteList middleware configuration.
// This middleware limits allowed requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
//
// Deprecated: please use IPAllowList instead.
type TCPIPWhiteList struct {
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
+2 -2
View File
@@ -13,7 +13,7 @@ import (
// KV pairs -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element.
func Decode(pairs []*store.KVPair, element interface{}, rootName string) error {
func Decode(pairs []*store.KVPair, element any, rootName string) error {
if element == nil {
return nil
}
@@ -34,7 +34,7 @@ func Decode(pairs []*store.KVPair, element interface{}, rootName string) error {
return parser.Fill(element, node, parser.FillerOpts{AllowSliceAsStruct: false})
}
func getRootFieldNames(rootName string, element interface{}) []string {
func getRootFieldNames(rootName string, element any) []string {
if element == nil {
return nil
}
+1 -1
View File
@@ -31,6 +31,6 @@ func EncodeConfiguration(conf *dynamic.Configuration) (map[string]string, error)
// Decode converts the labels to an element.
// labels -> [ node -> node + metadata (type) ] -> element (node).
func Decode(labels map[string]string, element interface{}, filters ...string) error {
func Decode(labels map[string]string, element any, filters ...string) error {
return parser.Decode(labels, element, parser.DefaultRootName, filters...)
}
+11 -17
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"maps"
"slices"
"sort"
"sync"
@@ -72,6 +73,7 @@ func unique(src []string) []string {
// RouterInfo holds information about a currently running HTTP router.
type RouterInfo struct {
*dynamic.Router // dynamic configuration
// Err contains all the errors that occurred during router's creation.
Err []string `json:"error,omitempty"`
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
@@ -84,10 +86,8 @@ type RouterInfo struct {
// AddError adds err to r.Err, if it does not already exist.
// If critical is set, r is marked as disabled.
func (r *RouterInfo) AddError(err error, critical bool) {
for _, value := range r.Err {
if value == err.Error() {
return
}
if slices.Contains(r.Err, err.Error()) {
return
}
r.Err = append(r.Err, err.Error())
@@ -105,6 +105,7 @@ func (r *RouterInfo) AddError(err error, critical bool) {
// MiddlewareInfo holds information about a currently running middleware.
type MiddlewareInfo struct {
*dynamic.Middleware // dynamic configuration
// Err contains all the errors that occurred during service creation.
Err []string `json:"error,omitempty"`
Status string `json:"status,omitempty"`
@@ -114,10 +115,8 @@ type MiddlewareInfo struct {
// AddError adds err to s.Err, if it does not already exist.
// If critical is set, m is marked as disabled.
func (m *MiddlewareInfo) AddError(err error, critical bool) {
for _, value := range m.Err {
if value == err.Error() {
return
}
if slices.Contains(m.Err, err.Error()) {
return
}
m.Err = append(m.Err, err.Error())
@@ -135,6 +134,7 @@ func (m *MiddlewareInfo) AddError(err error, critical bool) {
// ServiceInfo holds information about a currently running service.
type ServiceInfo struct {
*dynamic.Service // dynamic configuration
// Err contains all the errors that occurred during service creation.
Err []string `json:"error,omitempty"`
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
@@ -150,10 +150,8 @@ type ServiceInfo struct {
// AddError adds err to s.Err, if it does not already exist.
// If critical is set, s is marked as disabled.
func (s *ServiceInfo) AddError(err error, critical bool) {
for _, value := range s.Err {
if value == err.Error() {
return
}
if slices.Contains(s.Err, err.Error()) {
return
}
s.Err = append(s.Err, err.Error())
@@ -190,9 +188,5 @@ func (s *ServiceInfo) GetAllStatus() map[string]string {
return nil
}
allStatus := make(map[string]string, len(s.serverStatus))
for k, v := range s.serverStatus {
allStatus[k] = v
}
return allStatus
return maps.Clone(s.serverStatus)
}
+13 -16
View File
@@ -47,8 +47,9 @@ func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoi
// TCPRouterInfo holds information about a currently running TCP router.
type TCPRouterInfo struct {
*dynamic.TCPRouter // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
*dynamic.TCPRouter // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
// If not in "enabled" state, the reason for it should be in the list of Err.
// It is the caller's responsibility to set the initial status.
@@ -59,10 +60,8 @@ type TCPRouterInfo struct {
// AddError adds err to r.Err, if it does not already exist.
// If critical is set, r is marked as disabled.
func (r *TCPRouterInfo) AddError(err error, critical bool) {
for _, value := range r.Err {
if value == err.Error() {
return
}
if slices.Contains(r.Err, err.Error()) {
return
}
r.Err = append(r.Err, err.Error())
@@ -79,8 +78,9 @@ func (r *TCPRouterInfo) AddError(err error, critical bool) {
// TCPServiceInfo holds information about a currently running TCP service.
type TCPServiceInfo struct {
*dynamic.TCPService // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
*dynamic.TCPService // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
// If not in "enabled" state, the reason for it should be in the list of Err.
// It is the caller's responsibility to set the initial status.
@@ -91,10 +91,8 @@ type TCPServiceInfo struct {
// AddError adds err to s.Err, if it does not already exist.
// If critical is set, s is marked as disabled.
func (s *TCPServiceInfo) AddError(err error, critical bool) {
for _, value := range s.Err {
if value == err.Error() {
return
}
if slices.Contains(s.Err, err.Error()) {
return
}
s.Err = append(s.Err, err.Error())
@@ -112,6 +110,7 @@ func (s *TCPServiceInfo) AddError(err error, critical bool) {
// TCPMiddlewareInfo holds information about a currently running middleware.
type TCPMiddlewareInfo struct {
*dynamic.TCPMiddleware // dynamic configuration
// Err contains all the errors that occurred during service creation.
Err []string `json:"error,omitempty"`
Status string `json:"status,omitempty"`
@@ -121,10 +120,8 @@ type TCPMiddlewareInfo struct {
// AddError adds err to s.Err, if it does not already exist.
// If critical is set, m is marked as disabled.
func (m *TCPMiddlewareInfo) AddError(err error, critical bool) {
for _, value := range m.Err {
if value == err.Error() {
return
}
if slices.Contains(m.Err, err.Error()) {
return
}
m.Err = append(m.Err, err.Error())
+10 -12
View File
@@ -53,8 +53,9 @@ func (c *Configuration) GetUDPRoutersByEntryPoints(ctx context.Context, entryPoi
// UDPRouterInfo holds information about a currently running UDP router.
type UDPRouterInfo struct {
*dynamic.UDPRouter // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
*dynamic.UDPRouter // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
// If not in "enabled" state, the reason for it should be in the list of Err.
// It is the caller's responsibility to set the initial status.
@@ -65,10 +66,8 @@ type UDPRouterInfo struct {
// AddError adds err to r.Err, if it does not already exist.
// If critical is set, r is marked as disabled.
func (r *UDPRouterInfo) AddError(err error, critical bool) {
for _, value := range r.Err {
if value == err.Error() {
return
}
if slices.Contains(r.Err, err.Error()) {
return
}
r.Err = append(r.Err, err.Error())
@@ -85,8 +84,9 @@ func (r *UDPRouterInfo) AddError(err error, critical bool) {
// UDPServiceInfo holds information about a currently running UDP service.
type UDPServiceInfo struct {
*dynamic.UDPService // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
*dynamic.UDPService // dynamic configuration
Err []string `json:"error,omitempty"` // initialization error
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
// If not in "enabled" state, the reason for it should be in the list of Err.
// It is the caller's responsibility to set the initial status.
@@ -97,10 +97,8 @@ type UDPServiceInfo struct {
// AddError adds err to s.Err, if it does not already exist.
// If critical is set, s is marked as disabled.
func (s *UDPServiceInfo) AddError(err error, critical bool) {
for _, value := range s.Err {
if value == err.Error() {
return
}
if slices.Contains(s.Err, err.Error()) {
return
}
s.Err = append(s.Err, err.Error())
+1 -1
View File
@@ -1,4 +1,4 @@
package static
// PluginConf holds the plugin configuration.
type PluginConf map[string]interface{}
type PluginConf map[string]any
+14 -14
View File
@@ -295,20 +295,6 @@ func (c *Configuration) SetEffectiveConfiguration() {
c.initACMEProvider()
}
func (c *Configuration) hasUserDefinedEntrypoint() bool {
return len(c.EntryPoints) != 0
}
func (c *Configuration) initACMEProvider() {
for _, resolver := range c.CertificatesResolvers {
if resolver.ACME != nil {
resolver.ACME.CAServer = getSafeACMECAServer(resolver.ACME.CAServer)
}
}
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
}
// ValidateConfiguration validate that configuration is coherent.
func (c *Configuration) ValidateConfiguration() error {
var acmeEmail string
@@ -342,6 +328,20 @@ func (c *Configuration) ValidateConfiguration() error {
return nil
}
func (c *Configuration) hasUserDefinedEntrypoint() bool {
return len(c.EntryPoints) != 0
}
func (c *Configuration) initACMEProvider() {
for _, resolver := range c.CertificatesResolvers {
if resolver.ACME != nil {
resolver.ACME.CAServer = getSafeACMECAServer(resolver.ACME.CAServer)
}
}
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
}
func getSafeACMECAServer(caServerSrc string) string {
if len(caServerSrc) == 0 {
return DefaultAcmeCAServer
+19 -17
View File
@@ -82,10 +82,19 @@ type backendURL struct {
// BackendConfig HealthCheck configuration for a backend.
type BackendConfig struct {
Options
name string
disabledURLs []backendURL
}
// NewBackendConfig Instantiate a new BackendConfig.
func NewBackendConfig(options Options, backendName string) *BackendConfig {
return &BackendConfig{
Options: options,
name: backendName,
}
}
func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
u, err := serverURL.Parse(b.Path)
if err != nil {
@@ -236,14 +245,6 @@ func newHealthCheck(registry metrics.Registry) *HealthCheck {
}
}
// NewBackendConfig Instantiate a new BackendConfig.
func NewBackendConfig(options Options, backendName string) *BackendConfig {
return &BackendConfig{
Options: options,
name: backendName,
}
}
// checkHealth returns a nil error in case it was successful and otherwise
// a non-nil error with a meaningful description why the health check failed.
func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
@@ -286,6 +287,16 @@ type StatusUpdater interface {
RegisterStatusUpdater(fn func(up bool)) error
}
// LbStatusUpdater wraps a BalancerHandler and a ServiceInfo,
// so it can keep track of the status of a server in the ServiceInfo.
type LbStatusUpdater struct {
BalancerHandler
serviceInfo *runtime.ServiceInfo // can be nil
updaters []func(up bool)
wantsHealthCheck bool
}
// NewLBStatusUpdater returns a new LbStatusUpdater.
func NewLBStatusUpdater(bh BalancerHandler, info *runtime.ServiceInfo, hc *dynamic.ServerHealthCheck) *LbStatusUpdater {
return &LbStatusUpdater{
@@ -295,15 +306,6 @@ func NewLBStatusUpdater(bh BalancerHandler, info *runtime.ServiceInfo, hc *dynam
}
}
// LbStatusUpdater wraps a BalancerHandler and a ServiceInfo,
// so it can keep track of the status of a server in the ServiceInfo.
type LbStatusUpdater struct {
BalancerHandler
serviceInfo *runtime.ServiceInfo // can be nil
updaters []func(up bool)
wantsHealthCheck bool
}
// RegisterStatusUpdater adds fn to the list of hooks that are run when the
// status of the Balancer changes.
// Not thread safe.
+1
View File
@@ -456,6 +456,7 @@ type testLoadBalancer struct {
// RWMutex needed due to parallel test execution: Both the system-under-test
// and the test assertions reference the counters.
*sync.RWMutex
numRemovedServers int
numUpsertedServers int
servers []*url.URL
+1
View File
@@ -17,6 +17,7 @@ const (
// If operation() takes more than MinJobInterval, Reset() is called in NextBackOff().
type BackOff struct {
*backoff.ExponentialBackOff
MinJobInterval time.Duration
}
+24 -13
View File
@@ -9,68 +9,79 @@ import (
)
// Debug logs a message at level Debug on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Debug(...) instead.
func Debug(args ...interface{}) {
func Debug(args ...any) {
mainLogger.Debug(args...)
}
// Debugf logs a message at level Debug on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Debugf(...) instead.
func Debugf(format string, args ...interface{}) {
func Debugf(format string, args ...any) {
mainLogger.Debugf(format, args...)
}
// Info logs a message at level Info on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Info(...) instead.
func Info(args ...interface{}) {
func Info(args ...any) {
mainLogger.Info(args...)
}
// Infof logs a message at level Info on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Infof(...) instead.
func Infof(format string, args ...interface{}) {
func Infof(format string, args ...any) {
mainLogger.Infof(format, args...)
}
// Warn logs a message at level Warn on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Warn(...) instead.
func Warn(args ...interface{}) {
func Warn(args ...any) {
mainLogger.Warn(args...)
}
// Warnf logs a message at level Warn on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Warnf(...) instead.
func Warnf(format string, args ...interface{}) {
func Warnf(format string, args ...any) {
mainLogger.Warnf(format, args...)
}
// Error logs a message at level Error on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Error(...) instead.
func Error(args ...interface{}) {
func Error(args ...any) {
mainLogger.Error(args...)
}
// Errorf logs a message at level Error on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Errorf(...) instead.
func Errorf(format string, args ...interface{}) {
func Errorf(format string, args ...any) {
mainLogger.Errorf(format, args...)
}
// Panic logs a message at level Panic on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Panic(...) instead.
func Panic(args ...interface{}) {
func Panic(args ...any) {
mainLogger.Panic(args...)
}
// Fatal logs a message at level Fatal on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Fatal(...) instead.
func Fatal(args ...interface{}) {
func Fatal(args ...any) {
mainLogger.Fatal(args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
//
// Deprecated: use log.FromContext(ctx).Fatalf(...) instead.
func Fatalf(format string, args ...interface{}) {
func Fatalf(format string, args ...any) {
mainLogger.Fatalf(format, args...)
}
@@ -84,7 +95,7 @@ func AddHook(hook logrus.Hook) {
func CustomWriterLevel(level logrus.Level, maxScanTokenSize int) *io.PipeWriter {
reader, writer := io.Pipe()
var printFunc func(args ...interface{})
var printFunc func(args ...any)
switch level {
case logrus.DebugLevel:
@@ -111,7 +122,7 @@ func CustomWriterLevel(level logrus.Level, maxScanTokenSize int) *io.PipeWriter
// extract from github.com/Sirupsen/logrus/writer.go
// Hack the buffer size.
func writerScanner(reader io.ReadCloser, scanTokenSize int, printFunc func(args ...interface{})) {
func writerScanner(reader io.ReadCloser, scanTokenSize int, printFunc func(args ...any)) {
scanner := bufio.NewScanner(reader)
if scanTokenSize > bufio.MaxScanTokenSize {
+1 -1
View File
@@ -58,7 +58,7 @@ func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
config.Prefix = defaultMetricsPrefix
}
datadogClient = dogstatsd.New(config.Prefix+".", kitlog.LoggerFunc(func(keyvals ...interface{}) error {
datadogClient = dogstatsd.New(config.Prefix+".", kitlog.LoggerFunc(func(keyvals ...any) error {
log.WithoutContext().WithField(log.MetricsProviderName, "datadog").Info(keyvals...)
return nil
}))
+5 -5
View File
@@ -36,16 +36,16 @@ func (c MultiCounterWithHeaders) With(headers http.Header, labelValues ...string
return next
}
// NewCounterWithNoopHeaders returns a CounterWithNoopHeaders.
func NewCounterWithNoopHeaders(counter metrics.Counter) CounterWithNoopHeaders {
return CounterWithNoopHeaders{counter: counter}
}
// CounterWithNoopHeaders is a counter that satisfies CounterWithHeaders but ignores the given http.Header.
type CounterWithNoopHeaders struct {
counter metrics.Counter
}
// NewCounterWithNoopHeaders returns a CounterWithNoopHeaders.
func NewCounterWithNoopHeaders(counter metrics.Counter) CounterWithNoopHeaders {
return CounterWithNoopHeaders{counter: counter}
}
// Add adds the given delta value to the counter value.
func (c CounterWithNoopHeaders) Add(delta float64) {
c.counter.Add(delta)
+1 -1
View File
@@ -147,7 +147,7 @@ func initInfluxDBClient(ctx context.Context, config *types.InfluxDB) *influx.Inf
Database: config.Database,
RetentionPolicy: config.RetentionPolicy,
},
kitlog.LoggerFunc(func(keyvals ...interface{}) error {
kitlog.LoggerFunc(func(keyvals ...any) error {
log.WithoutContext().WithField(log.MetricsProviderName, "influxdb").Info(keyvals...)
return nil
}))
+1 -1
View File
@@ -37,7 +37,7 @@ func RegisterInfluxDB2(ctx context.Context, config *types.InfluxDB2) Registry {
influxDB2Store = influx.New(
config.AdditionalLabels,
influxdb.BatchPointsConfig{},
kitlog.LoggerFunc(func(kv ...interface{}) error {
kitlog.LoggerFunc(func(kv ...any) error {
log.FromContext(ctx).Error(kv...)
return nil
}),
+1 -1
View File
@@ -55,7 +55,7 @@ func RegisterStatsd(ctx context.Context, config *types.Statsd) Registry {
config.Prefix = defaultMetricsPrefix
}
statsdClient = statsd.New(config.Prefix+".", kitlog.LoggerFunc(func(keyvals ...interface{}) error {
statsdClient = statsd.New(config.Prefix+".", kitlog.LoggerFunc(func(keyvals ...any) error {
log.WithoutContext().WithField(log.MetricsProviderName, "statsd").Info(keyvals...)
return nil
}))
+1 -1
View File
@@ -121,7 +121,7 @@ func init() {
}
// CoreLogData holds the fields computed from the request/response.
type CoreLogData map[string]interface{}
type CoreLogData map[string]any
// LogData is the data captured by the middleware so that it can be logged.
type LogData struct {
@@ -52,7 +52,7 @@ func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
return b.Bytes(), err
}
func toLog(fields logrus.Fields, key, defaultValue string, quoted bool) interface{} {
func toLog(fields logrus.Fields, key, defaultValue string, quoted bool) any {
if v, ok := fields[key]; ok {
if v == nil {
return defaultValue
@@ -14,12 +14,12 @@ func TestCommonLogFormatter_Format(t *testing.T) {
testCases := []struct {
name string
data map[string]interface{}
data map[string]any
expectedLog string
}{
{
name: "DownstreamStatus & DownstreamContentSize are nil",
data: map[string]interface{}{
data: map[string]any{
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
Duration: 123 * time.Second,
ClientHost: "10.0.0.1",
@@ -40,7 +40,7 @@ func TestCommonLogFormatter_Format(t *testing.T) {
},
{
name: "all data",
data: map[string]interface{}{
data: map[string]any{
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
Duration: 123 * time.Second,
ClientHost: "10.0.0.1",
@@ -61,7 +61,7 @@ func TestCommonLogFormatter_Format(t *testing.T) {
},
{
name: "all data with local time",
data: map[string]interface{}{
data: map[string]any{
StartLocal: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
Duration: 123 * time.Second,
ClientHost: "10.0.0.1",
@@ -106,7 +106,7 @@ func Test_toLog(t *testing.T) {
fieldName string
defaultValue string
quoted bool
expectedLog interface{}
expectedLog any
}{
{
desc: "Should return int 1",
+20 -20
View File
@@ -116,7 +116,7 @@ func lineCount(t *testing.T, fileName string) int {
}
count := 0
for _, line := range strings.Split(string(fileContents), "\n") {
for line := range strings.SplitSeq(string(fileContents), "\n") {
if strings.TrimSpace(line) == "" {
continue
}
@@ -259,32 +259,32 @@ func TestLoggerCLFWithBufferingSize(t *testing.T) {
assertValidLogData(t, expectedLog, logData)
}
func assertString(exp string) func(t *testing.T, actual interface{}) {
return func(t *testing.T, actual interface{}) {
func assertString(exp string) func(t *testing.T, actual any) {
return func(t *testing.T, actual any) {
t.Helper()
assert.Equal(t, exp, actual)
}
}
func assertNotEmpty() func(t *testing.T, actual interface{}) {
return func(t *testing.T, actual interface{}) {
func assertNotEmpty() func(t *testing.T, actual any) {
return func(t *testing.T, actual any) {
t.Helper()
assert.NotEmpty(t, actual)
}
}
func assertFloat64(exp float64) func(t *testing.T, actual interface{}) {
return func(t *testing.T, actual interface{}) {
func assertFloat64(exp float64) func(t *testing.T, actual any) {
return func(t *testing.T, actual any) {
t.Helper()
assert.InDelta(t, exp, actual, delta)
}
}
func assertFloat64NotZero() func(t *testing.T, actual interface{}) {
return func(t *testing.T, actual interface{}) {
func assertFloat64NotZero() func(t *testing.T, actual any) {
return func(t *testing.T, actual any) {
t.Helper()
assert.NotZero(t, actual)
@@ -296,7 +296,7 @@ func TestLoggerJSON(t *testing.T) {
desc string
config *types.AccessLog
tls bool
expected map[string]func(t *testing.T, value interface{})
expected map[string]func(t *testing.T, value any)
}{
{
desc: "default config",
@@ -304,7 +304,7 @@ func TestLoggerJSON(t *testing.T) {
FilePath: "",
Format: JSONFormat,
},
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
RequestContentSize: assertFloat64(0),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
@@ -344,7 +344,7 @@ func TestLoggerJSON(t *testing.T) {
Format: JSONFormat,
},
tls: true,
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
RequestContentSize: assertFloat64(0),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
@@ -388,7 +388,7 @@ func TestLoggerJSON(t *testing.T) {
DefaultMode: "drop",
},
},
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEmpty(),
@@ -409,7 +409,7 @@ func TestLoggerJSON(t *testing.T) {
},
},
},
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEmpty(),
@@ -427,7 +427,7 @@ func TestLoggerJSON(t *testing.T) {
},
},
},
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEmpty(),
@@ -454,7 +454,7 @@ func TestLoggerJSON(t *testing.T) {
},
},
},
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
RequestHost: assertString(testHostname),
"level": assertString("info"),
"msg": assertString(""),
@@ -480,7 +480,7 @@ func TestLoggerJSON(t *testing.T) {
},
},
},
expected: map[string]func(t *testing.T, value interface{}){
expected: map[string]func(t *testing.T, value any){
RequestHost: assertString(testHostname),
"level": assertString("info"),
"msg": assertString(""),
@@ -506,7 +506,7 @@ func TestLoggerJSON(t *testing.T) {
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
jsonData := make(map[string]interface{})
jsonData := make(map[string]any)
err = json.Unmarshal(logData, &jsonData)
require.NoError(t, err)
@@ -520,7 +520,7 @@ func TestLoggerJSON(t *testing.T) {
}
func TestLogger_AbortedRequest(t *testing.T) {
expected := map[string]func(t *testing.T, value interface{}){
expected := map[string]func(t *testing.T, value any){
RequestContentSize: assertFloat64(0),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
@@ -563,7 +563,7 @@ func TestLogger_AbortedRequest(t *testing.T) {
logData, err := os.ReadFile(config.FilePath)
require.NoError(t, err)
jsonData := make(map[string]interface{})
jsonData := make(map[string]any)
err = json.Unmarshal(logData, &jsonData)
require.NoError(t, err)
+1 -1
View File
@@ -22,7 +22,7 @@ func RemoveConnectionHeaders(req *http.Request) {
}
for _, f := range req.Header[connectionHeader] {
for _, sf := range strings.Split(f, ",") {
for sf := range strings.SplitSeq(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
req.Header.Del(sf)
}
+14 -14
View File
@@ -84,20 +84,6 @@ func (c *Capture) Reset(next http.Handler) http.Handler {
})
}
func (c *Capture) renew(rw http.ResponseWriter, req *http.Request) (http.ResponseWriter, *http.Request) {
ctx := context.WithValue(req.Context(), capturedData, c)
newReq := req.WithContext(ctx)
if newReq.Body != nil {
readCounter := &readCounter{source: newReq.Body}
c.rr = readCounter
newReq.Body = readCounter
}
c.rw = newResponseWriter(rw)
return c.rw, newReq
}
func (c *Capture) ResponseSize() int64 {
return c.rw.Size()
}
@@ -115,6 +101,20 @@ func (c *Capture) RequestSize() int64 {
return c.rr.size
}
func (c *Capture) renew(rw http.ResponseWriter, req *http.Request) (http.ResponseWriter, *http.Request) {
ctx := context.WithValue(req.Context(), capturedData, c)
newReq := req.WithContext(ctx)
if newReq.Body != nil {
readCounter := &readCounter{source: newReq.Body}
c.rr = readCounter
newReq.Body = readCounter
}
c.rw = newResponseWriter(rw)
return c.rw, newReq
}
type readCounter struct {
// source ReadCloser from where the request body is read.
source io.ReadCloser
+17 -22
View File
@@ -4,6 +4,7 @@ import (
"bufio"
"context"
"fmt"
"maps"
"net"
"net/http"
"net/url"
@@ -169,16 +170,6 @@ func (cc *codeCatcher) Header() http.Header {
return cc.headerMap
}
func (cc *codeCatcher) getCode() int {
return cc.code
}
// isFilteredCode returns whether the codeCatcher received a response code among the ones it is watching,
// and for which the response should be deferred to the error handler.
func (cc *codeCatcher) isFilteredCode() bool {
return cc.caughtFilteredCode
}
func (cc *codeCatcher) Write(buf []byte) (int, error) {
// If WriteHeader was already called from the caller, this is a NOOP.
// Otherwise, cc.code is actually a 200 here.
@@ -204,9 +195,7 @@ func (cc *codeCatcher) WriteHeader(code int) {
if code >= 100 && code <= 199 {
// Multiple informational status codes can be used,
// so here the copy is not appending the values to not repeat them.
for k, v := range cc.Header() {
cc.responseWriter.Header()[k] = v
}
maps.Copy(cc.responseWriter.Header(), cc.Header())
cc.responseWriter.WriteHeader(code)
return
@@ -224,9 +213,8 @@ func (cc *codeCatcher) WriteHeader(code int) {
// The copy is not appending the values,
// to not repeat them in case any informational status code has been written.
for k, v := range cc.Header() {
cc.responseWriter.Header()[k] = v
}
maps.Copy(cc.responseWriter.Header(), cc.Header())
cc.responseWriter.WriteHeader(cc.code)
cc.headersSent = true
}
@@ -259,6 +247,16 @@ func (cc *codeCatcher) Flush() {
}
}
func (cc *codeCatcher) getCode() int {
return cc.code
}
// isFilteredCode returns whether the codeCatcher received a response code among the ones it is watching,
// and for which the response should be deferred to the error handler.
func (cc *codeCatcher) isFilteredCode() bool {
return cc.caughtFilteredCode
}
type codeCatcherWithCloseNotify struct {
*codeCatcher
}
@@ -332,17 +330,14 @@ func (r *codeModifierWithoutCloseNotify) WriteHeader(code int) {
if code >= 100 && code <= 199 {
// Multiple informational status codes can be used,
// so here the copy is not appending the values to not repeat them.
for k, v := range r.headerMap {
r.responseWriter.Header()[k] = v
}
maps.Copy(r.responseWriter.Header(), r.headerMap)
r.responseWriter.WriteHeader(code)
return
}
for k, v := range r.headerMap {
r.responseWriter.Header()[k] = v
}
maps.Copy(r.responseWriter.Header(), r.headerMap)
r.responseWriter.WriteHeader(r.code)
r.headerSent = true
}
@@ -81,13 +81,6 @@ func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []strin
}, nil
}
func (x *XForwarded) isTrustedIP(ip string) bool {
if x.ipChecker == nil {
return false
}
return x.ipChecker.IsAuthorized(ip) == nil
}
// removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has {zone} information in it,
// like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 Ethernet Adapter - Virtual Switch)]:64692".
func removeIPv6Zone(clientIP string) string {
@@ -138,6 +131,28 @@ func forwardedPort(req *http.Request) string {
return "80"
}
// ServeHTTP implements http.Handler.
func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !x.insecure && !x.isTrustedIP(r.RemoteAddr) {
for _, h := range xHeaders {
unsafeHeader(r.Header).Del(h)
}
}
x.rewrite(r)
x.removeConnectionHeaders(r)
x.next.ServeHTTP(w, r)
}
func (x *XForwarded) isTrustedIP(ip string) bool {
if x.ipChecker == nil {
return false
}
return x.ipChecker.IsAuthorized(ip) == nil
}
func (x *XForwarded) rewrite(outreq *http.Request) {
if clientIP, _, err := net.SplitHostPort(outreq.RemoteAddr); err == nil {
clientIP = removeIPv6Zone(clientIP)
@@ -186,21 +201,6 @@ func (x *XForwarded) rewrite(outreq *http.Request) {
}
}
// ServeHTTP implements http.Handler.
func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !x.insecure && !x.isTrustedIP(r.RemoteAddr) {
for _, h := range xHeaders {
unsafeHeader(r.Header).Del(h)
}
}
x.rewrite(r)
x.removeConnectionHeaders(r)
x.next.ServeHTTP(w, r)
}
func (x *XForwarded) removeConnectionHeaders(req *http.Request) {
var reqUpType string
if httpguts.HeaderValuesContainsToken(req.Header[connection], upgrade) {
@@ -209,7 +209,7 @@ func (x *XForwarded) removeConnectionHeaders(req *http.Request) {
var connectionHopByHopHeaders []string
for _, f := range req.Header[connection] {
for _, sf := range strings.Split(f, ",") {
for sf := range strings.SplitSeq(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
// Connection header cannot dictate to remove X- headers managed by Traefik,
// as per rfc7230 https://datatracker.ietf.org/doc/html/rfc7230#section-6.1,
+21 -21
View File
@@ -68,27 +68,6 @@ func (s *Header) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
// modifyCustomRequestHeaders sets or deletes custom request headers.
func (s *Header) modifyCustomRequestHeaders(req *http.Request) {
// Loop through Custom request headers
for header, value := range s.headers.CustomRequestHeaders {
switch {
// Handling https://github.com/golang/go/commit/ecdbffd4ec68b509998792f120868fec319de59b.
case value == "" && header == forward.XForwardedFor:
req.Header[header] = nil
case value == "":
req.Header.Del(header)
case strings.EqualFold(header, "Host"):
req.Host = value
default:
req.Header.Set(header, value)
}
}
}
// PostRequestModifyResponseHeaders set or delete response headers.
// This method is called AFTER the response is generated from the backend
// and can merge/override headers from the backend response.
@@ -138,6 +117,27 @@ func (s *Header) PostRequestModifyResponseHeaders(res *http.Response) error {
return nil
}
// modifyCustomRequestHeaders sets or deletes custom request headers.
func (s *Header) modifyCustomRequestHeaders(req *http.Request) {
// Loop through Custom request headers
for header, value := range s.headers.CustomRequestHeaders {
switch {
// Handling https://github.com/golang/go/commit/ecdbffd4ec68b509998792f120868fec319de59b.
case value == "" && header == forward.XForwardedFor:
req.Header[header] = nil
case value == "":
req.Header.Del(header)
case strings.EqualFold(header, "Host"):
req.Host = value
default:
req.Header.Set(header, value)
}
}
}
// processCorsHeaders processes the incoming request,
// and returns if it is a preflight request.
// If not a preflight, it handles the preRequestModifyCorsResponseHeaders.
+2 -1
View File
@@ -18,10 +18,11 @@ func Test_newSecure_sslForceHost(t *testing.T) {
}
testCases := []struct {
expected
desc string
host string
cfg dynamic.Headers
expected
}{
{
desc: "http should return a 301",
+5 -4
View File
@@ -27,6 +27,7 @@ func newResponseRecorder(rw http.ResponseWriter) recorder {
// later analysis.
type responseRecorder struct {
http.ResponseWriter
statusCode int
}
@@ -40,10 +41,6 @@ func (r *responseRecorderWithCloseNotify) CloseNotify() <-chan bool {
return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
}
func (r *responseRecorder) getCode() int {
return r.statusCode
}
// WriteHeader captures the status code for later retrieval.
func (r *responseRecorder) WriteHeader(status int) {
r.ResponseWriter.WriteHeader(status)
@@ -61,3 +58,7 @@ func (r *responseRecorder) Flush() {
f.Flush()
}
}
func (r *responseRecorder) getCode() int {
return r.statusCode
}
+1 -4
View File
@@ -66,10 +66,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.RateLimit, name
return nil, err
}
burst := config.Burst
if burst < 1 {
burst = 1
}
burst := max(config.Burst, 1)
period := time.Duration(config.Period)
if period < 0 {
@@ -283,11 +283,8 @@ func TestRateLimit(t *testing.T) {
stop := time.Now()
elapsed := stop.Sub(start)
burst := test.config.Burst
if burst < 1 {
// actual default value
burst = 1
}
// actual default value if burst < 1
burst := max(test.config.Burst, 1)
period := time.Duration(test.config.Period)
if period == 0 {
+1 -1
View File
@@ -57,7 +57,7 @@ func recoverFunc(rw recoveryResponseWriter, r *http.Request) {
// https://github.com/golang/go/blob/a0d6420d8be2ae7164797051ec74fa2a2df466a1/src/net/http/server.go#L1761-L1775
// https://github.com/golang/go/blob/c33153f7b416c03983324b3e8f869ce1116d84bc/src/net/http/httputil/reverseproxy.go#L284
func shouldLogPanic(panicValue interface{}) bool {
func shouldLogPanic(panicValue any) bool {
//nolint:errorlint // false-positive because panicValue is an interface.
return panicValue != nil && panicValue != http.ErrAbortHandler
}
+2 -4
View File
@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"io"
"maps"
"math"
"net"
"net/http"
@@ -239,10 +240,7 @@ func (r *responseWriterWithoutCloseNotify) WriteHeader(code int) {
// to write headers to the backend : we are not going to perform any further retry.
// So it is now safe to alter current response headers with headers collected during
// the latest try before writing headers to client.
headers := r.responseWriter.Header()
for header, value := range r.headers {
headers[header] = value
}
maps.Copy(r.responseWriter.Header(), r.headers)
r.responseWriter.WriteHeader(code)
+1
View File
@@ -29,6 +29,7 @@ func NewEntryPoint(ctx context.Context, t *tracing.Tracing, entryPointName strin
type entryPointMiddleware struct {
*tracing.Tracing
entryPoint string
next http.Handler
}
+5 -5
View File
@@ -13,7 +13,7 @@ import (
func TestEntryPointMiddleware(t *testing.T) {
type expected struct {
Tags map[string]interface{}
Tags map[string]any
OperationName string
}
@@ -29,10 +29,10 @@ func TestEntryPointMiddleware(t *testing.T) {
entryPoint: "test",
spanNameLimit: 0,
tracing: &trackingBackenMock{
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}},
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]any)}},
},
expected: expected{
Tags: map[string]interface{}{
Tags: map[string]any{
"span.kind": ext.SpanKindRPCServerEnum,
"http.method": http.MethodGet,
"component": "",
@@ -47,10 +47,10 @@ func TestEntryPointMiddleware(t *testing.T) {
entryPoint: "test",
spanNameLimit: 25,
tracing: &trackingBackenMock{
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}},
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]any)}},
},
expected: expected{
Tags: map[string]interface{}{
Tags: map[string]any{
"span.kind": ext.SpanKindRPCServerEnum,
"http.method": http.MethodGet,
"component": "",
+9 -9
View File
@@ -13,7 +13,7 @@ import (
func TestNewForwarder(t *testing.T) {
type expected struct {
Tags map[string]interface{}
Tags map[string]any
OperationName string
}
@@ -29,12 +29,12 @@ func TestNewForwarder(t *testing.T) {
desc: "Simple Forward Tracer without truncation and hashing",
spanNameLimit: 101,
tracing: &trackingBackenMock{
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}},
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]any)}},
},
service: "some-service.domain.tld",
router: "some-service.domain.tld",
expected: expected{
Tags: map[string]interface{}{
Tags: map[string]any{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
@@ -49,12 +49,12 @@ func TestNewForwarder(t *testing.T) {
desc: "Simple Forward Tracer with truncation and hashing",
spanNameLimit: 101,
tracing: &trackingBackenMock{
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}},
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]any)}},
},
service: "some-service-100.slug.namespace.environment.domain.tld",
router: "some-service-100.slug.namespace.environment.domain.tld",
expected: expected{
Tags: map[string]interface{}{
Tags: map[string]any{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
@@ -69,12 +69,12 @@ func TestNewForwarder(t *testing.T) {
desc: "Exactly 101 chars",
spanNameLimit: 101,
tracing: &trackingBackenMock{
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}},
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]any)}},
},
service: "some-service1.namespace.environment.domain.tld",
router: "some-service1.namespace.environment.domain.tld",
expected: expected{
Tags: map[string]interface{}{
Tags: map[string]any{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
@@ -89,12 +89,12 @@ func TestNewForwarder(t *testing.T) {
desc: "More than 101 chars",
spanNameLimit: 101,
tracing: &trackingBackenMock{
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}},
tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]any)}},
},
service: "some-service1.frontend.namespace.environment.domain.tld",
router: "some-service1.backend.namespace.environment.domain.tld",
expected: expected{
Tags: map[string]interface{}{
Tags: map[string]any{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
+8 -8
View File
@@ -18,12 +18,12 @@ func (n MockTracer) StartSpan(operationName string, opts ...opentracing.StartSpa
}
// Inject belongs to the Tracer interface.
func (n MockTracer) Inject(sp opentracing.SpanContext, format, carrier interface{}) error {
func (n MockTracer) Inject(sp opentracing.SpanContext, format, carrier any) error {
return nil
}
// Extract belongs to the Tracer interface.
func (n MockTracer) Extract(format, carrier interface{}) (opentracing.SpanContext, error) {
func (n MockTracer) Extract(format, carrier any) (opentracing.SpanContext, error) {
return nil, opentracing.ErrSpanContextNotFound
}
@@ -35,29 +35,29 @@ func (n MockSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {}
// MockSpan a span mock.
type MockSpan struct {
OpName string
Tags map[string]interface{}
Tags map[string]any
}
func (n *MockSpan) Context() opentracing.SpanContext { return MockSpanContext{} }
func (n *MockSpan) SetBaggageItem(key, val string) opentracing.Span {
return &MockSpan{Tags: make(map[string]interface{})}
return &MockSpan{Tags: make(map[string]any)}
}
func (n *MockSpan) BaggageItem(key string) string { return "" }
func (n *MockSpan) SetTag(key string, value interface{}) opentracing.Span {
func (n *MockSpan) SetTag(key string, value any) opentracing.Span {
n.Tags[key] = value
return n
}
func (n *MockSpan) LogFields(fields ...log.Field) {}
func (n *MockSpan) LogKV(keyVals ...interface{}) {}
func (n *MockSpan) LogKV(keyVals ...any) {}
func (n *MockSpan) Finish() {}
func (n *MockSpan) FinishWithOptions(opts opentracing.FinishOptions) {}
func (n *MockSpan) SetOperationName(operationName string) opentracing.Span { return n }
func (n *MockSpan) Tracer() opentracing.Tracer { return MockTracer{} }
func (n *MockSpan) LogEvent(event string) {}
func (n *MockSpan) LogEventWithPayload(event string, payload interface{}) {}
func (n *MockSpan) LogEventWithPayload(event string, payload any) {}
func (n *MockSpan) Log(data opentracing.LogData) {}
func (n *MockSpan) Reset() {
n.Tags = make(map[string]interface{})
n.Tags = make(map[string]any)
}
type trackingBackenMock struct {
+1
View File
@@ -22,6 +22,7 @@ func newStatusCodeRecoder(rw http.ResponseWriter, status int) statusCodeRecoder
type statusCodeWithoutCloseNotify struct {
http.ResponseWriter
status int
}
+1
View File
@@ -32,6 +32,7 @@ var httpFuncs = map[string]func(*mux.Route, ...string) error{
// Muxer handles routing with rules.
type Muxer struct {
*mux.Router
parser predicate.Parser
}
+29 -29
View File
@@ -245,35 +245,6 @@ func (c *Client) Unzip(pName, pVersion string) error {
return c.unzipArchive(pName, pVersion)
}
func (c *Client) unzipModule(pName, pVersion string) error {
src := c.buildArchivePath(pName, pVersion)
dest := filepath.Join(c.sources, filepath.FromSlash(pName))
return zip.Unzip(dest, module.Version{Path: pName, Version: pVersion}, src)
}
func (c *Client) unzipArchive(pName, pVersion string) error {
zipPath := c.buildArchivePath(pName, pVersion)
archive, err := zipa.OpenReader(zipPath)
if err != nil {
return err
}
defer func() { _ = archive.Close() }()
dest := filepath.Join(c.sources, filepath.FromSlash(pName))
for _, f := range archive.File {
err = unzipFile(f, dest)
if err != nil {
return fmt.Errorf("unable to unzip %s: %w", f.Name, err)
}
}
return nil
}
func unzipFile(f *zipa.File, dest string) error {
rc, err := f.Open()
if err != nil {
@@ -404,6 +375,35 @@ func (c *Client) ResetAll() error {
return nil
}
func (c *Client) unzipModule(pName, pVersion string) error {
src := c.buildArchivePath(pName, pVersion)
dest := filepath.Join(c.sources, filepath.FromSlash(pName))
return zip.Unzip(dest, module.Version{Path: pName, Version: pVersion}, src)
}
func (c *Client) unzipArchive(pName, pVersion string) error {
zipPath := c.buildArchivePath(pName, pVersion)
archive, err := zipa.OpenReader(zipPath)
if err != nil {
return err
}
defer func() { _ = archive.Close() }()
dest := filepath.Join(c.sources, filepath.FromSlash(pName))
for _, f := range archive.File {
err = unzipFile(f, dest)
if err != nil {
return fmt.Errorf("unable to unzip %s: %w", f.Name, err)
}
}
return nil
}
func (c *Client) buildArchivePath(pName, pVersion string) string {
return filepath.Join(c.archives, filepath.FromSlash(pName), pVersion+".zip")
}
+3 -3
View File
@@ -13,7 +13,7 @@ import (
)
// Build builds a middleware plugin.
func (b Builder) Build(pName string, config map[string]interface{}, middlewareName string) (Constructor, error) {
func (b Builder) Build(pName string, config map[string]any, middlewareName string) (Constructor, error) {
if b.middlewareBuilders == nil {
return nil, fmt.Errorf("no plugin definition in the static configuration: %s", pName)
}
@@ -77,7 +77,7 @@ func (p middlewareBuilder) newHandler(ctx context.Context, next http.Handler, cf
return handler, nil
}
func (p middlewareBuilder) createConfig(config map[string]interface{}) (reflect.Value, error) {
func (p middlewareBuilder) createConfig(config map[string]any) (reflect.Value, error) {
results := p.fnCreateConfig.Call(nil)
if len(results) != 1 {
return reflect.Value{}, fmt.Errorf("invalid number of return for the CreateConfig function: %d", len(results))
@@ -114,7 +114,7 @@ type Middleware struct {
builder *middlewareBuilder
}
func newMiddleware(builder *middlewareBuilder, config map[string]interface{}, middlewareName string) (*Middleware, error) {
func newMiddleware(builder *middlewareBuilder, config map[string]any, middlewareName string) (*Middleware, error) {
vConfig, err := builder.createConfig(config)
if err != nil {
return nil, err
+3 -3
View File
@@ -24,7 +24,7 @@ type PP interface {
}
type _PP struct {
IValue interface{}
IValue any
WInit func() error
WProvide func(cfgChan chan<- json.Marshaler) error
WStop func() error
@@ -52,7 +52,7 @@ func ppSymbols() map[string]map[string]reflect.Value {
}
// BuildProvider builds a plugin's provider.
func (b Builder) BuildProvider(pName string, config map[string]interface{}) (provider.Provider, error) {
func (b Builder) BuildProvider(pName string, config map[string]any) (provider.Provider, error) {
if b.providerBuilders == nil {
return nil, fmt.Errorf("no plugin definition in the static configuration: %s", pName)
}
@@ -81,7 +81,7 @@ type Provider struct {
pp PP
}
func newProvider(builder providerBuilder, config map[string]interface{}, providerName string) (*Provider, error) {
func newProvider(builder providerBuilder, config map[string]any, providerName string) (*Provider, error) {
basePkg := builder.BasePkg
if basePkg == "" {
basePkg = strings.ReplaceAll(path.Base(builder.Import), "-", "_")
+7 -7
View File
@@ -17,11 +17,11 @@ type LocalDescriptor struct {
// Manifest The plugin manifest.
type Manifest struct {
DisplayName string `yaml:"displayName"`
Type string `yaml:"type"`
Import string `yaml:"import"`
BasePkg string `yaml:"basePkg"`
Compatibility string `yaml:"compatibility"`
Summary string `yaml:"summary"`
TestData map[string]interface{} `yaml:"testData"`
DisplayName string `yaml:"displayName"`
Type string `yaml:"type"`
Import string `yaml:"import"`
BasePkg string `yaml:"basePkg"`
Compatibility string `yaml:"compatibility"`
Summary string `yaml:"summary"`
TestData map[string]any `yaml:"testData"`
}
+49 -53
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"io"
"maps"
"os"
"sync"
@@ -29,6 +30,52 @@ func NewLocalStore(filename string, routinesPool *safe.Pool) *LocalStore {
return store
}
// GetAccount returns ACME Account.
func (s *LocalStore) GetAccount(resolverName string) (*Account, error) {
storedData, err := s.get(resolverName)
if err != nil {
return nil, err
}
return storedData.Account, nil
}
// SaveAccount stores ACME Account.
func (s *LocalStore) SaveAccount(resolverName string, account *Account) error {
storedData, err := s.get(resolverName)
if err != nil {
return err
}
storedData.Account = account
s.save(resolverName, storedData)
return nil
}
// GetCertificates returns ACME Certificates list.
func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, error) {
storedData, err := s.get(resolverName)
if err != nil {
return nil, err
}
return storedData.Certificates, nil
}
// SaveCertificates stores ACME Certificates list.
func (s *LocalStore) SaveCertificates(resolverName string, certificates []*CertAndStore) error {
storedData, err := s.get(resolverName)
if err != nil {
return err
}
storedData.Certificates = certificates
s.save(resolverName, storedData)
return nil
}
func (s *LocalStore) save(resolverName string, storedData *StoredData) {
s.lock.Lock()
defer s.lock.Unlock()
@@ -121,8 +168,7 @@ func (s *LocalStore) listenSaveAction(routinesPool *safe.Pool) {
logger.Error(err)
}
err = os.WriteFile(s.filename, data, 0o600)
if err != nil {
if err := os.WriteFile(s.filename, data, 0o600); err != nil {
logger.Error(err)
}
}
@@ -132,55 +178,5 @@ func (s *LocalStore) listenSaveAction(routinesPool *safe.Pool) {
// unSafeCopyOfStoredData creates maps copy of storedData. Is not thread safe, you should use `s.lock`.
func (s *LocalStore) unSafeCopyOfStoredData() map[string]*StoredData {
result := map[string]*StoredData{}
for k, v := range s.storedData {
result[k] = v
}
return result
}
// GetAccount returns ACME Account.
func (s *LocalStore) GetAccount(resolverName string) (*Account, error) {
storedData, err := s.get(resolverName)
if err != nil {
return nil, err
}
return storedData.Account, nil
}
// SaveAccount stores ACME Account.
func (s *LocalStore) SaveAccount(resolverName string, account *Account) error {
storedData, err := s.get(resolverName)
if err != nil {
return err
}
storedData.Account = account
s.save(resolverName, storedData)
return nil
}
// GetCertificates returns ACME Certificates list.
func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, error) {
storedData, err := s.get(resolverName)
if err != nil {
return nil, err
}
return storedData.Certificates, nil
}
// SaveCertificates stores ACME Certificates list.
func (s *LocalStore) SaveCertificates(resolverName string, certificates []*CertAndStore) error {
storedData, err := s.get(resolverName)
if err != nil {
return err
}
storedData.Certificates = certificates
s.save(resolverName, storedData)
return nil
return maps.Clone(s.storedData)
}
-1
View File
@@ -1,5 +1,4 @@
//go:build !windows
// +build !windows
package acme
+3 -1
View File
@@ -58,6 +58,7 @@ func (a *Configuration) SetDefaults() {
// CertAndStore allows mapping a TLS certificate to a TLS store.
type CertAndStore struct {
Certificate
Store string
}
@@ -93,6 +94,7 @@ type TLSChallenge struct{}
// Provider holds configurations of the provider.
type Provider struct {
*Configuration
ResolverName string
Store Store `json:"store,omitempty" toml:"store,omitempty" yaml:"store,omitempty"`
@@ -955,7 +957,7 @@ func (p *Provider) certExists(validDomains []string) bool {
func isDomainAlreadyChecked(domainToCheck string, existentDomains []string) bool {
for _, certDomains := range existentDomains {
for _, certDomain := range strings.Split(certDomains, ",") {
for certDomain := range strings.SplitSeq(certDomains, ",") {
if types.MatchDomain(domainToCheck, certDomain) {
return true
}
+7 -7
View File
@@ -145,13 +145,6 @@ func NewProviderAggregator(conf static.Providers) *ProviderAggregator {
return p
}
func (p *ProviderAggregator) quietAddProvider(provider provider.Provider) {
err := p.AddProvider(provider)
if err != nil {
log.WithoutContext().Errorf("Error while initializing provider %T: %v", provider, err)
}
}
// AddProvider adds a provider in the providers map.
func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
err := provider.Init()
@@ -197,6 +190,13 @@ func (p *ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, p
return nil
}
func (p *ProviderAggregator) quietAddProvider(provider provider.Provider) {
err := p.AddProvider(provider)
if err != nil {
log.WithoutContext().Errorf("Error while initializing provider %T: %v", provider, err)
}
}
func (p *ProviderAggregator) launchProvider(configurationChan chan<- dynamic.Message, pool *safe.Pool, prd provider.Provider) {
jsonConf, err := redactor.RemoveCredentials(prd)
if err != nil {
+2 -4
View File
@@ -364,9 +364,7 @@ func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*tem
defaultFuncMap := sprig.TxtFuncMap()
defaultFuncMap["normalize"] = Normalize
for k, fn := range funcMap {
defaultFuncMap[k] = fn
}
maps.Copy(defaultFuncMap, funcMap)
return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
}
@@ -419,7 +417,7 @@ func BuildUDPRouterConfiguration(ctx context.Context, configuration *dynamic.UDP
}
// BuildRouterConfiguration builds a router configuration.
func BuildRouterConfiguration(ctx context.Context, configuration *dynamic.HTTPConfiguration, defaultRouterName string, defaultRuleTpl *template.Template, model interface{}) {
func BuildRouterConfiguration(ctx context.Context, configuration *dynamic.HTTPConfiguration, defaultRouterName string, defaultRuleTpl *template.Template, model any) {
if len(configuration.Routers) == 0 {
if len(configuration.Services) > 1 {
log.FromContext(ctx).Info("Could not create a router for the container: too many services")
@@ -30,7 +30,7 @@ func MatchLabels(labels map[string]string, expr string) (bool, error) {
NOT: notLabelFunc,
OR: orLabelFunc,
},
Functions: map[string]interface{}{
Functions: map[string]any{
"Label": labelFn,
"LabelRegex": labelRegexFn,
"MarathonConstraint": marathonFn,
+1 -1
View File
@@ -25,7 +25,7 @@ func MatchTags(tags []string, expr string) (bool, error) {
NOT: notTagFunc,
OR: orTagFunc,
},
Functions: map[string]interface{}{
Functions: map[string]any{
"Tag": tagFn,
"TagRegex": tagRegexFn,
},
+10 -10
View File
@@ -394,12 +394,12 @@ func (p *Provider) fetchService(ctx context.Context, name string, connectEnabled
// watchServices watches for update events of the services list and statuses,
// and transmits them to the caller through the p.watchServicesChan.
func (p *Provider) watchServices(ctx context.Context) error {
servicesWatcher, err := watch.Parse(map[string]interface{}{"type": "services"})
servicesWatcher, err := watch.Parse(map[string]any{"type": "services"})
if err != nil {
return fmt.Errorf("failed to create services watcher plan: %w", err)
}
servicesWatcher.HybridHandler = func(_ watch.BlockingParamVal, _ interface{}) {
servicesWatcher.HybridHandler = func(_ watch.BlockingParamVal, _ any) {
select {
case <-ctx.Done():
case p.watchServicesChan <- struct{}{}:
@@ -408,12 +408,12 @@ func (p *Provider) watchServices(ctx context.Context) error {
}
}
checksWatcher, err := watch.Parse(map[string]interface{}{"type": "checks"})
checksWatcher, err := watch.Parse(map[string]any{"type": "checks"})
if err != nil {
return fmt.Errorf("failed to create checks watcher plan: %w", err)
}
checksWatcher.HybridHandler = func(_ watch.BlockingParamVal, _ interface{}) {
checksWatcher.HybridHandler = func(_ watch.BlockingParamVal, _ any) {
select {
case <-ctx.Done():
case p.watchServicesChan <- struct{}{}:
@@ -452,8 +452,8 @@ func (p *Provider) watchServices(ctx context.Context) error {
}
}
func rootsWatchHandler(ctx context.Context, dest chan<- []string) func(watch.BlockingParamVal, interface{}) {
return func(_ watch.BlockingParamVal, raw interface{}) {
func rootsWatchHandler(ctx context.Context, dest chan<- []string) func(watch.BlockingParamVal, any) {
return func(_ watch.BlockingParamVal, raw any) {
if raw == nil {
log.FromContext(ctx).Errorf("Root certificate watcher called with nil")
return
@@ -482,8 +482,8 @@ type keyPair struct {
key string
}
func leafWatcherHandler(ctx context.Context, dest chan<- keyPair) func(watch.BlockingParamVal, interface{}) {
return func(_ watch.BlockingParamVal, raw interface{}) {
func leafWatcherHandler(ctx context.Context, dest chan<- keyPair) func(watch.BlockingParamVal, any) {
return func(_ watch.BlockingParamVal, raw any) {
if raw == nil {
log.FromContext(ctx).Errorf("Leaf certificate watcher called with nil")
return
@@ -511,7 +511,7 @@ func leafWatcherHandler(ctx context.Context, dest chan<- keyPair) func(watch.Blo
// certificate, and transmits them to the caller via p.certChan.
func (p *Provider) watchConnectTLS(ctx context.Context) error {
leafChan := make(chan keyPair)
leafWatcher, err := watch.Parse(map[string]interface{}{
leafWatcher, err := watch.Parse(map[string]any{
"type": "connect_leaf",
"service": p.ServiceName,
})
@@ -521,7 +521,7 @@ func (p *Provider) watchConnectTLS(ctx context.Context) error {
leafWatcher.HybridHandler = leafWatcherHandler(ctx, leafChan)
rootsChan := make(chan []string)
rootsWatcher, err := watch.Parse(map[string]interface{}{
rootsWatcher, err := watch.Parse(map[string]any{
"type": "connect_roots",
})
if err != nil {
+73 -73
View File
@@ -104,79 +104,6 @@ type networkData struct {
ID string
}
func (p *Provider) createClient() (client.APIClient, error) {
opts, err := p.getClientOpts()
if err != nil {
return nil, err
}
httpHeaders := map[string]string{
"User-Agent": "Traefik " + version.Version,
}
opts = append(opts,
client.FromEnv,
client.WithAPIVersionNegotiation(),
client.WithHTTPHeaders(httpHeaders))
return client.NewClientWithOpts(opts...)
}
func (p *Provider) getClientOpts() ([]client.Opt, error) {
helper, err := connhelper.GetConnectionHelper(p.Endpoint)
if err != nil {
return nil, err
}
// SSH
if helper != nil {
// https://github.com/docker/cli/blob/ebca1413117a3fcb81c89d6be226dcec74e5289f/cli/context/docker/load.go#L112-L123
httpClient := &http.Client{
Transport: &http.Transport{
DialContext: helper.Dialer,
},
}
return []client.Opt{
client.WithHTTPClient(httpClient),
client.WithTimeout(time.Duration(p.HTTPClientTimeout)),
client.WithHost(helper.Host), // To avoid 400 Bad Request: malformed Host header daemon error
client.WithDialContext(helper.Dialer),
}, nil
}
opts := []client.Opt{
client.WithHost(p.Endpoint),
client.WithTimeout(time.Duration(p.HTTPClientTimeout)),
}
if p.TLS != nil {
ctx := log.With(context.Background(), log.Str(log.ProviderName, "docker"))
conf, err := p.TLS.CreateTLSConfig(ctx)
if err != nil {
return nil, fmt.Errorf("unable to create client TLS configuration: %w", err)
}
hostURL, err := client.ParseHostURL(p.Endpoint)
if err != nil {
return nil, err
}
tr := &http.Transport{
TLSClientConfig: conf,
}
if err := sockets.ConfigureTransport(tr, hostURL.Scheme, hostURL.Host); err != nil {
return nil, err
}
opts = append(opts, client.WithHTTPClient(&http.Client{Transport: tr, Timeout: time.Duration(p.HTTPClientTimeout)}))
}
return opts, nil
}
// Provide allows the docker provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
pool.GoCtx(func(routineCtx context.Context) {
@@ -327,6 +254,79 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) createClient() (client.APIClient, error) {
opts, err := p.getClientOpts()
if err != nil {
return nil, err
}
httpHeaders := map[string]string{
"User-Agent": "Traefik " + version.Version,
}
opts = append(opts,
client.FromEnv,
client.WithAPIVersionNegotiation(),
client.WithHTTPHeaders(httpHeaders))
return client.NewClientWithOpts(opts...)
}
func (p *Provider) getClientOpts() ([]client.Opt, error) {
helper, err := connhelper.GetConnectionHelper(p.Endpoint)
if err != nil {
return nil, err
}
// SSH
if helper != nil {
// https://github.com/docker/cli/blob/ebca1413117a3fcb81c89d6be226dcec74e5289f/cli/context/docker/load.go#L112-L123
httpClient := &http.Client{
Transport: &http.Transport{
DialContext: helper.Dialer,
},
}
return []client.Opt{
client.WithHTTPClient(httpClient),
client.WithTimeout(time.Duration(p.HTTPClientTimeout)),
client.WithHost(helper.Host), // To avoid 400 Bad Request: malformed Host header daemon error
client.WithDialContext(helper.Dialer),
}, nil
}
opts := []client.Opt{
client.WithHost(p.Endpoint),
client.WithTimeout(time.Duration(p.HTTPClientTimeout)),
}
if p.TLS != nil {
ctx := log.With(context.Background(), log.Str(log.ProviderName, "docker"))
conf, err := p.TLS.CreateTLSConfig(ctx)
if err != nil {
return nil, fmt.Errorf("unable to create client TLS configuration: %w", err)
}
hostURL, err := client.ParseHostURL(p.Endpoint)
if err != nil {
return nil, err
}
tr := &http.Transport{
TLSClientConfig: conf,
}
if err := sockets.ConfigureTransport(tr, hostURL.Scheme, hostURL.Host); err != nil {
return nil, err
}
opts = append(opts, client.WithHTTPClient(&http.Client{Transport: tr, Timeout: time.Duration(p.HTTPClientTimeout)}))
}
return opts, nil
}
func (p *Provider) listContainers(ctx context.Context, dockerClient client.ContainerAPIClient) ([]dockerData, error) {
containerList, err := dockerClient.ContainerList(ctx, dockercontainertypes.ListOptions{})
if err != nil {
+2
View File
@@ -17,6 +17,7 @@ import (
type fakeTasksClient struct {
dockerclient.APIClient
tasks []swarmtypes.Task
container dockercontainertypes.InspectResponse
err error
@@ -105,6 +106,7 @@ func TestListTasks(t *testing.T) {
type fakeServicesClient struct {
dockerclient.APIClient
dockerVersion string
networks []networktypes.Summary
nodes []swarmtypes.Node
+37 -37
View File
@@ -101,43 +101,6 @@ func (p *Provider) Init() error {
return nil
}
func (p *Provider) createClient(ctx context.Context, logger log.Logger) (*awsClient, error) {
optFns := []func(*config.LoadOptions) error{
config.WithLogger(logging.LoggerFunc(func(_ logging.Classification, format string, args ...interface{}) {
logger.Debugf(format, args...)
})),
}
if p.Region != "" {
optFns = append(optFns, config.WithRegion(p.Region))
} else {
logger.Infoln("No region provided, will retrieve region from the EC2 Metadata service")
optFns = append(optFns, config.WithEC2IMDSRegion())
}
if p.AccessKeyID != "" && p.SecretAccessKey != "" {
// From https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specify-credentials-programmatically:
// "If you explicitly provide credentials, as in this example, the SDK uses only those credentials."
// this makes sure that user-defined credentials always have the highest priority
staticCreds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(p.AccessKeyID, p.SecretAccessKey, ""))
optFns = append(optFns, config.WithCredentialsProvider(staticCreds))
// If the access key and secret access key are not provided, config.LoadDefaultConfig
// will look for the credentials in the default credential chain.
// See https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials.
}
cfg, err := config.LoadDefaultConfig(ctx, optFns...)
if err != nil {
return nil, err
}
return &awsClient{
ecs.NewFromConfig(cfg),
ec2.NewFromConfig(cfg),
ssm.NewFromConfig(cfg),
}, nil
}
// Provide configuration to traefik from ECS.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
pool.GoCtx(func(routineCtx context.Context) {
@@ -184,6 +147,43 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) createClient(ctx context.Context, logger log.Logger) (*awsClient, error) {
optFns := []func(*config.LoadOptions) error{
config.WithLogger(logging.LoggerFunc(func(_ logging.Classification, format string, args ...any) {
logger.Debugf(format, args...)
})),
}
if p.Region != "" {
optFns = append(optFns, config.WithRegion(p.Region))
} else {
logger.Infoln("No region provided, will retrieve region from the EC2 Metadata service")
optFns = append(optFns, config.WithEC2IMDSRegion())
}
if p.AccessKeyID != "" && p.SecretAccessKey != "" {
// From https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specify-credentials-programmatically:
// "If you explicitly provide credentials, as in this example, the SDK uses only those credentials."
// this makes sure that user-defined credentials always have the highest priority
staticCreds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(p.AccessKeyID, p.SecretAccessKey, ""))
optFns = append(optFns, config.WithCredentialsProvider(staticCreds))
// If the access key and secret access key are not provided, config.LoadDefaultConfig
// will look for the credentials in the default credential chain.
// See https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials.
}
cfg, err := config.LoadDefaultConfig(ctx, optFns...)
if err != nil {
return nil, err
}
return &awsClient{
ecs.NewFromConfig(cfg),
ec2.NewFromConfig(cfg),
ssm.NewFromConfig(cfg),
}, nil
}
func (p *Provider) loadConfiguration(ctx context.Context, client *awsClient, configurationChan chan<- dynamic.Message) error {
instances, err := p.listInstances(ctx, client)
if err != nil {
+46 -47
View File
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"maps"
"os"
"path"
"path/filepath"
@@ -106,6 +107,51 @@ func (p *Provider) BuildConfiguration() (*dynamic.Configuration, error) {
return nil, errors.New("error using file configuration provider, neither filename or directory defined")
}
// CreateConfiguration creates a provider configuration from content using templating.
func (p *Provider) CreateConfiguration(ctx context.Context, filename string, funcMap template.FuncMap, templateObjects any) (*dynamic.Configuration, error) {
tmplContent, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %w", filename, err)
}
defaultFuncMap := sprig.TxtFuncMap()
defaultFuncMap["normalize"] = provider.Normalize
defaultFuncMap["split"] = strings.Split
maps.Copy(defaultFuncMap, funcMap)
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
_, err = tmpl.Parse(tmplContent)
if err != nil {
return nil, err
}
var buffer bytes.Buffer
err = tmpl.Execute(&buffer, templateObjects)
if err != nil {
return nil, err
}
renderedTemplate := buffer.String()
if p.DebugLogGeneratedTemplate {
logger := log.FromContext(ctx)
logger.Debugf("Template content: %s", tmplContent)
logger.Debugf("Rendering results: %s", renderedTemplate)
}
return p.decodeConfiguration(filename, renderedTemplate)
}
// DecodeConfiguration Decodes a *types.Configuration from a content.
func (p *Provider) DecodeConfiguration(filename string) (*dynamic.Configuration, error) {
content, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %w", filename, err)
}
return p.decodeConfiguration(filename, content)
}
func (p *Provider) addWatcher(pool *safe.Pool, items []string, configurationChan chan<- dynamic.Message, callback func(chan<- dynamic.Message, fsnotify.Event)) error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
@@ -470,53 +516,6 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
return configuration, nil
}
// CreateConfiguration creates a provider configuration from content using templating.
func (p *Provider) CreateConfiguration(ctx context.Context, filename string, funcMap template.FuncMap, templateObjects interface{}) (*dynamic.Configuration, error) {
tmplContent, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %w", filename, err)
}
defaultFuncMap := sprig.TxtFuncMap()
defaultFuncMap["normalize"] = provider.Normalize
defaultFuncMap["split"] = strings.Split
for funcID, funcElement := range funcMap {
defaultFuncMap[funcID] = funcElement
}
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
_, err = tmpl.Parse(tmplContent)
if err != nil {
return nil, err
}
var buffer bytes.Buffer
err = tmpl.Execute(&buffer, templateObjects)
if err != nil {
return nil, err
}
renderedTemplate := buffer.String()
if p.DebugLogGeneratedTemplate {
logger := log.FromContext(ctx)
logger.Debugf("Template content: %s", tmplContent)
logger.Debugf("Rendering results: %s", renderedTemplate)
}
return p.decodeConfiguration(filename, renderedTemplate)
}
// DecodeConfiguration Decodes a *types.Configuration from a content.
func (p *Provider) DecodeConfiguration(filename string) (*dynamic.Configuration, error) {
content, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %w", filename, err)
}
return p.decodeConfiguration(filename, content)
}
func (p *Provider) decodeConfiguration(filePath, content string) (*dynamic.Configuration, error) {
configuration := &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
@@ -21,19 +21,19 @@ func (c *clientWrapper) appendContainousIngressRoutes(result []*traefikv1alpha1.
for ns, factory := range c.factoriesCrd {
ings, err := factory.TraefikContainous().V1alpha1().IngressRoutes().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list ingress routes in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list ingress routes in namespace %s: %v", ns, err)
}
for _, ing := range ings {
key := objectKey(ing.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 ingress route (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 ingress route (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(ing, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert ingress route in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert ingress route in namespace %s: %v", ns, err)
continue
}
@@ -53,19 +53,19 @@ func (c *clientWrapper) appendContainousIngressRouteTCPs(result []*traefikv1alph
for ns, factory := range c.factoriesCrd {
ings, err := factory.TraefikContainous().V1alpha1().IngressRouteTCPs().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tcp ingress routes in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tcp ingress routes in namespace %s: %v", ns, err)
}
for _, ing := range ings {
key := objectKey(ing.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 tcp ingress route (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 tcp ingress route (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(ing, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert tcp ingress route in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert tcp ingress route in namespace %s: %v", ns, err)
continue
}
@@ -85,19 +85,19 @@ func (c *clientWrapper) appendContainousIngressRouteUDPs(result []*traefikv1alph
for ns, factory := range c.factoriesCrd {
ings, err := factory.TraefikContainous().V1alpha1().IngressRouteUDPs().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list udp ingress routes in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list udp ingress routes in namespace %s: %v", ns, err)
}
for _, ing := range ings {
key := objectKey(ing.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 udp ingress route (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 udp ingress route (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(ing, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert udp ingress route in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert udp ingress route in namespace %s: %v", ns, err)
continue
}
@@ -117,19 +117,19 @@ func (c *clientWrapper) appendContainousMiddlewares(result []*traefikv1alpha1.Mi
for ns, factory := range c.factoriesCrd {
middlewares, err := factory.TraefikContainous().V1alpha1().Middlewares().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list middlewares in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list middlewares in namespace %s: %v", ns, err)
}
for _, middleware := range middlewares {
key := objectKey(middleware.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 middleware (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 middleware (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(middleware, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert middleware in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert middleware in namespace %s: %v", ns, err)
continue
}
@@ -149,19 +149,19 @@ func (c *clientWrapper) appendContainousMiddlewareTCPs(result []*traefikv1alpha1
for ns, factory := range c.factoriesCrd {
middlewares, err := factory.TraefikContainous().V1alpha1().MiddlewareTCPs().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tcp middlewares in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tcp middlewares in namespace %s: %v", ns, err)
}
for _, middleware := range middlewares {
key := objectKey(middleware.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 middleware (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 middleware (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(middleware, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert tcp middleware in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert tcp middleware in namespace %s: %v", ns, err)
continue
}
@@ -181,19 +181,19 @@ func (c *clientWrapper) appendContainousTraefikServices(result []*traefikv1alpha
for ns, factory := range c.factoriesCrd {
traefikServices, err := factory.TraefikContainous().V1alpha1().TraefikServices().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list Traefik services in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list Traefik services in namespace %s: %v", ns, err)
}
for _, traefikService := range traefikServices {
key := objectKey(traefikService.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 Traefik service (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 Traefik service (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(traefikService, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert Traefik service in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert Traefik service in namespace %s: %v", ns, err)
continue
}
@@ -213,19 +213,19 @@ func (c *clientWrapper) appendContainousServersTransport(result []*traefikv1alph
for ns, factory := range c.factoriesCrd {
serversTransports, err := factory.TraefikContainous().V1alpha1().ServersTransports().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list servers transports in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list servers transports in namespace %s: %v", ns, err)
}
for _, serversTransport := range serversTransports {
key := objectKey(serversTransport.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 servers transport (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 servers transport (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(serversTransport, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert servers transport in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert servers transport in namespace %s: %v", ns, err)
continue
}
@@ -245,19 +245,19 @@ func (c *clientWrapper) appendContainousTLSOptions(result []*traefikv1alpha1.TLS
for ns, factory := range c.factoriesCrd {
options, err := factory.TraefikContainous().V1alpha1().TLSOptions().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tls options in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tls options in namespace %s: %v", ns, err)
}
for _, option := range options {
key := objectKey(option.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 tls option (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 tls option (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(option, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert tls option in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert tls option in namespace %s: %v", ns, err)
continue
}
@@ -277,19 +277,19 @@ func (c *clientWrapper) appendContainousTLSStores(result []*traefikv1alpha1.TLSS
for ns, factory := range c.factoriesCrd {
stores, err := factory.TraefikContainous().V1alpha1().TLSStores().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tls stores in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tls stores in namespace %s: %v", ns, err)
}
for _, store := range stores {
key := objectKey(store.ObjectMeta)
if _, ok := listed[key]; ok {
log.Debugf("Ignoring traefik.containo.us/v1alpha1 tls store (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
log.WithoutContext().Debugf("Ignoring traefik.containo.us/v1alpha1 tls store (%s) already listed within traefik.io/v1alpha1 API GroupVersion", key)
continue
}
toVersion, err := traefikscheme.Scheme.ConvertToVersion(store, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert tls store in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to convert tls store in namespace %s: %v", ns, err)
continue
}
@@ -314,7 +314,7 @@ func (c *clientWrapper) getContainousTraefikService(namespace, name string) (*tr
toVersion, err := traefikscheme.Scheme.ConvertToVersion(service, GroupVersioner)
if err != nil {
log.Errorf("Failed to convert Traefik service in namespace %s: %v", namespace, err)
log.WithoutContext().Errorf("Failed to convert Traefik service in namespace %s: %v", namespace, err)
}
return toVersion.(*traefikv1alpha1.TraefikService), exist, err
+12 -12
View File
@@ -31,7 +31,7 @@ const resyncPeriod = 10 * time.Minute
// WatchAll starts the watch of the Provider resources and updates the stores.
// The stores can then be accessed via the Get* functions.
type Client interface {
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error)
GetIngressRoutes() []*traefikv1alpha1.IngressRoute
GetIngressRouteTCPs() []*traefikv1alpha1.IngressRouteTCP
GetIngressRouteUDPs() []*traefikv1alpha1.IngressRouteUDP
@@ -143,8 +143,8 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrappe
}
// WatchAll starts namespace-specific controllers for all relevant kinds.
func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
eventCh := make(chan interface{}, 1)
func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error) {
eventCh := make(chan any, 1)
eventHandler := &k8s.ResourceEventHandler{Ev: eventCh}
if len(namespaces) == 0 {
@@ -262,7 +262,7 @@ func (c *clientWrapper) GetIngressRoutes() []*traefikv1alpha1.IngressRoute {
for ns, factory := range c.factoriesCrd {
ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list ingress routes in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list ingress routes in namespace %s: %v", ns, err)
}
result = append(result, ings...)
}
@@ -276,7 +276,7 @@ func (c *clientWrapper) GetIngressRouteTCPs() []*traefikv1alpha1.IngressRouteTCP
for ns, factory := range c.factoriesCrd {
ings, err := factory.Traefik().V1alpha1().IngressRouteTCPs().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tcp ingress routes in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tcp ingress routes in namespace %s: %v", ns, err)
}
result = append(result, ings...)
}
@@ -290,7 +290,7 @@ func (c *clientWrapper) GetIngressRouteUDPs() []*traefikv1alpha1.IngressRouteUDP
for ns, factory := range c.factoriesCrd {
ings, err := factory.Traefik().V1alpha1().IngressRouteUDPs().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list udp ingress routes in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list udp ingress routes in namespace %s: %v", ns, err)
}
result = append(result, ings...)
}
@@ -304,7 +304,7 @@ func (c *clientWrapper) GetMiddlewares() []*traefikv1alpha1.Middleware {
for ns, factory := range c.factoriesCrd {
middlewares, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list middlewares in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list middlewares in namespace %s: %v", ns, err)
}
result = append(result, middlewares...)
}
@@ -318,7 +318,7 @@ func (c *clientWrapper) GetMiddlewareTCPs() []*traefikv1alpha1.MiddlewareTCP {
for ns, factory := range c.factoriesCrd {
middlewares, err := factory.Traefik().V1alpha1().MiddlewareTCPs().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list TCP middlewares in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list TCP middlewares in namespace %s: %v", ns, err)
}
result = append(result, middlewares...)
}
@@ -348,7 +348,7 @@ func (c *clientWrapper) GetTraefikServices() []*traefikv1alpha1.TraefikService {
for ns, factory := range c.factoriesCrd {
traefikServices, err := factory.Traefik().V1alpha1().TraefikServices().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list Traefik services in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list Traefik services in namespace %s: %v", ns, err)
}
result = append(result, traefikServices...)
}
@@ -363,7 +363,7 @@ func (c *clientWrapper) GetServersTransports() []*traefikv1alpha1.ServersTranspo
for ns, factory := range c.factoriesCrd {
serversTransports, err := factory.Traefik().V1alpha1().ServersTransports().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list servers transport in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list servers transport in namespace %s: %v", ns, err)
}
result = append(result, serversTransports...)
}
@@ -378,7 +378,7 @@ func (c *clientWrapper) GetTLSOptions() []*traefikv1alpha1.TLSOption {
for ns, factory := range c.factoriesCrd {
options, err := factory.Traefik().V1alpha1().TLSOptions().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tls options in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tls options in namespace %s: %v", ns, err)
}
result = append(result, options...)
}
@@ -393,7 +393,7 @@ func (c *clientWrapper) GetTLSStores() []*traefikv1alpha1.TLSStore {
for ns, factory := range c.factoriesCrd {
stores, err := factory.Traefik().V1alpha1().TLSStores().Lister().List(labels.Everything())
if err != nil {
log.Errorf("Failed to list tls stores in namespace %s: %v", ns, err)
log.WithoutContext().Errorf("Failed to list tls stores in namespace %s: %v", ns, err)
}
result = append(result, stores...)
}
@@ -40,7 +40,7 @@ type clientMock struct {
traefikServices []*traefikv1alpha1.TraefikService
serversTransport []*traefikv1alpha1.ServersTransport
watchChan chan interface{}
watchChan chan any
}
func newClientMock(paths ...string) clientMock {
@@ -184,6 +184,6 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
return nil, false, nil
}
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error) {
return c.watchChan, nil
}
+49 -49
View File
@@ -67,50 +67,6 @@ func (p *Provider) SetRouterTransform(routerTransform k8s.RouterTransform) {
p.routerTransform = routerTransform
}
func (p *Provider) applyRouterTransform(ctx context.Context, rt *dynamic.Router, ingress *traefikv1alpha1.IngressRoute) {
if p.routerTransform == nil {
return
}
err := p.routerTransform.Apply(ctx, rt, ingress.Annotations)
if err != nil {
log.FromContext(ctx).WithError(err).Error("Apply router transform")
}
}
func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
_, err := labels.Parse(p.LabelSelector)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %q", p.LabelSelector)
}
log.FromContext(ctx).Infof("label selector is: %q", p.LabelSelector)
withEndpoint := ""
if p.Endpoint != "" {
withEndpoint = fmt.Sprintf(" with endpoint %s", p.Endpoint)
}
var client *clientWrapper
switch {
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
log.FromContext(ctx).Infof("Creating in-cluster Provider client%s", withEndpoint)
client, err = newInClusterClient(p.Endpoint)
case os.Getenv("KUBECONFIG") != "":
log.FromContext(ctx).Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
default:
log.FromContext(ctx).Infof("Creating cluster-external Provider client%s", withEndpoint)
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
}
if err != nil {
return nil, err
}
client.labelSelector = p.LabelSelector
return client, nil
}
// Init the provider.
func (p *Provider) Init() error {
return nil
@@ -201,6 +157,50 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) applyRouterTransform(ctx context.Context, rt *dynamic.Router, ingress *traefikv1alpha1.IngressRoute) {
if p.routerTransform == nil {
return
}
err := p.routerTransform.Apply(ctx, rt, ingress.Annotations)
if err != nil {
log.FromContext(ctx).WithError(err).Error("Apply router transform")
}
}
func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
_, err := labels.Parse(p.LabelSelector)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %q", p.LabelSelector)
}
log.FromContext(ctx).Infof("label selector is: %q", p.LabelSelector)
withEndpoint := ""
if p.Endpoint != "" {
withEndpoint = fmt.Sprintf(" with endpoint %s", p.Endpoint)
}
var client *clientWrapper
switch {
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
log.FromContext(ctx).Infof("Creating in-cluster Provider client%s", withEndpoint)
client, err = newInClusterClient(p.Endpoint)
case os.Getenv("KUBECONFIG") != "":
log.FromContext(ctx).Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
default:
log.FromContext(ctx).Infof("Creating cluster-external Provider client%s", withEndpoint)
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
}
if err != nil {
return nil, err
}
client.labelSelector = p.LabelSelector
return client, nil
}
func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) *dynamic.Configuration {
stores, tlsConfigs := buildTLSStores(ctx, client)
if tlsConfigs == nil {
@@ -488,7 +488,7 @@ func createPluginMiddleware(k8sClient Client, ns string, plugins map[string]apie
return pcMap, nil
}
func loadSecretKeys(k8sClient Client, ns string, i interface{}) (interface{}, error) {
func loadSecretKeys(k8sClient Client, ns string, i any) (any, error) {
var err error
switch iv := i.(type) {
case string:
@@ -498,14 +498,14 @@ func loadSecretKeys(k8sClient Client, ns string, i interface{}) (interface{}, er
return getSecretValue(k8sClient, ns, iv)
case []interface{}:
case []any:
for i := range iv {
if iv[i], err = loadSecretKeys(k8sClient, ns, iv[i]); err != nil {
return nil, err
}
}
case map[string]interface{}:
case map[string]any:
for k := range iv {
if iv[k], err = loadSecretKeys(k8sClient, ns, iv[k]); err != nil {
return nil, err
@@ -1149,12 +1149,12 @@ func getCABlocks(secret *corev1.Secret, namespace, secretName string) (string, e
return "", fmt.Errorf("secret %s/%s contains neither tls.ca nor ca.crt", namespace, secretName)
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan any) chan any {
if throttleDuration == 0 {
return nil
}
// Create a buffered channel to hold the pending event (if we're delaying processing the event due to throttling)
eventsChanBuffered := make(chan interface{}, 1)
eventsChanBuffered := make(chan any, 1)
// Run a goroutine that reads events from eventChan and does a non-blocking write to pendingEvent.
// This guarantees that writing to eventChan will never block,
+11 -11
View File
@@ -3411,7 +3411,7 @@ func TestLoadIngressRoutes(t *testing.T) {
Middlewares: map[string]*dynamic.Middleware{
"default-test-secret": {
Plugin: map[string]dynamic.PluginConf{
"test-secret": map[string]interface{}{
"test-secret": map[string]any{
"user": "admin",
"secret": "this_is_the_secret",
},
@@ -3442,10 +3442,10 @@ func TestLoadIngressRoutes(t *testing.T) {
Middlewares: map[string]*dynamic.Middleware{
"default-test-secret": {
Plugin: map[string]dynamic.PluginConf{
"test-secret": map[string]interface{}{
"secret_0": map[string]interface{}{
"secret_1": map[string]interface{}{
"secret_2": map[string]interface{}{
"test-secret": map[string]any{
"secret_0": map[string]any{
"secret_1": map[string]any{
"secret_2": map[string]any{
"user": "admin",
"secret": "this_is_the_very_deep_secret",
},
@@ -3479,8 +3479,8 @@ func TestLoadIngressRoutes(t *testing.T) {
Middlewares: map[string]*dynamic.Middleware{
"default-test-secret": {
Plugin: map[string]dynamic.PluginConf{
"test-secret": map[string]interface{}{
"secret": []interface{}{"secret_data1", "secret_data2"},
"test-secret": map[string]any{
"secret": []any{"secret_data1", "secret_data2"},
},
},
},
@@ -3509,13 +3509,13 @@ func TestLoadIngressRoutes(t *testing.T) {
Middlewares: map[string]*dynamic.Middleware{
"default-test-secret": {
Plugin: map[string]dynamic.PluginConf{
"test-secret": map[string]interface{}{
"users": []interface{}{
map[string]interface{}{
"test-secret": map[string]any{
"users": []any{
map[string]any{
"name": "admin",
"secret": "admin_password",
},
map[string]interface{}{
map[string]any{
"name": "user",
"secret": "user_password",
},
+2 -2
View File
@@ -29,7 +29,7 @@ func init() {
kschema.GroupKind{Group: containousv1alpha1.GroupName, Kind: containousv1alpha1.TraefikService{}.Kind},
)
convert := map[interface{}]interface{}{}
convert := map[any]any{}
convert[&containousv1alpha1.IngressRoute{}] = &traefikv1alpha1.IngressRoute{}
convert[&containousv1alpha1.IngressRouteTCP{}] = &traefikv1alpha1.IngressRouteTCP{}
convert[&containousv1alpha1.IngressRouteUDP{}] = &traefikv1alpha1.IngressRouteUDP{}
@@ -41,7 +41,7 @@ func init() {
convert[&containousv1alpha1.TraefikService{}] = &traefikv1alpha1.TraefikService{}
for interfaceA, interfaceB := range convert {
err := traefikscheme.Scheme.AddConversionFunc(interfaceA, interfaceB, func(a, b interface{}, scope conversion.Scope) error {
err := traefikscheme.Scheme.AddConversionFunc(interfaceA, interfaceB, func(a, b any, scope conversion.Scope) error {
unstruct, err := k8sruntime.DefaultUnstructuredConverter.ToUnstructured(a)
if err != nil {
return fmt.Errorf("failed to unstruct interface: %w", err)
@@ -27,8 +27,9 @@ type MiddlewareTCPSpec struct {
InFlightConn *dynamic.TCPInFlightConn `json:"inFlightConn,omitempty"`
// IPWhiteList defines the IPWhiteList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
// Deprecated: please use IPAllowList instead.
// More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
//
// Deprecated: please use IPAllowList instead.
IPWhiteList *dynamic.TCPIPWhiteList `json:"ipWhiteList,omitempty"`
// IPAllowList defines the IPAllowList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
@@ -43,6 +43,7 @@ type TLSOptionSpec struct {
SniStrict bool `json:"sniStrict,omitempty"`
// PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
// It is enabled automatically when minVersion or maxVersion is set.
//
// Deprecated: https://github.com/golang/go/issues/45430
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty"`
// ALPNProtocols defines the list of supported application level protocols for the TLS handshake, in order of preference.
@@ -27,8 +27,9 @@ type MiddlewareTCPSpec struct {
InFlightConn *dynamic.TCPInFlightConn `json:"inFlightConn,omitempty"`
// IPWhiteList defines the IPWhiteList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
// Deprecated: please use IPAllowList instead.
// More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
//
// Deprecated: please use IPAllowList instead.
IPWhiteList *dynamic.TCPIPWhiteList `json:"ipWhiteList,omitempty"`
// IPAllowList defines the IPAllowList middleware configuration.
// This middleware accepts/refuses connections based on the client IP.
@@ -43,6 +43,7 @@ type TLSOptionSpec struct {
SniStrict bool `json:"sniStrict,omitempty"`
// PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
// It is enabled automatically when minVersion or maxVersion is set.
//
// Deprecated: https://github.com/golang/go/issues/45430
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty"`
// ALPNProtocols defines the list of supported application level protocols for the TLS handshake, in order of preference.
+8 -8
View File
@@ -25,14 +25,14 @@ import (
const resyncPeriod = 10 * time.Minute
type resourceEventHandler struct {
ev chan<- interface{}
ev chan<- any
}
func (reh *resourceEventHandler) OnAdd(obj interface{}, _ bool) {
func (reh *resourceEventHandler) OnAdd(obj any, _ bool) {
eventHandlerFunc(reh.ev, obj)
}
func (reh *resourceEventHandler) OnUpdate(oldObj, newObj interface{}) {
func (reh *resourceEventHandler) OnUpdate(oldObj, newObj any) {
switch oldObj.(type) {
case *gatev1alpha2.GatewayClass:
// Skip update for gateway classes. We only manage addition or deletion for this cluster-wide resource.
@@ -42,7 +42,7 @@ func (reh *resourceEventHandler) OnUpdate(oldObj, newObj interface{}) {
}
}
func (reh *resourceEventHandler) OnDelete(obj interface{}) {
func (reh *resourceEventHandler) OnDelete(obj any) {
eventHandlerFunc(reh.ev, obj)
}
@@ -50,7 +50,7 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
// WatchAll starts the watch of the Provider resources and updates the stores.
// The stores can then be accessed via the Get* functions.
type Client interface {
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error)
GetGatewayClasses() ([]*gatev1alpha2.GatewayClass, error)
UpdateGatewayStatus(gateway *gatev1alpha2.Gateway, gatewayStatus gatev1alpha2.GatewayStatus) error
UpdateGatewayClassStatus(gatewayClass *gatev1alpha2.GatewayClass, condition metav1.Condition) error
@@ -152,8 +152,8 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrappe
}
// WatchAll starts namespace-specific controllers for all relevant kinds.
func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
eventCh := make(chan interface{}, 1)
func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error) {
eventCh := make(chan any, 1)
eventHandler := &resourceEventHandler{ev: eventCh}
if len(namespaces) == 0 {
@@ -527,7 +527,7 @@ func (c *clientWrapper) lookupNamespace(ns string) string {
// eventHandlerFunc will pass the obj on to the events channel or drop it.
// This is so passing the events along won't block in the case of high volume.
// The events are only used for signaling anyway so dropping a few is ok.
func eventHandlerFunc(events chan<- interface{}, obj interface{}) {
func eventHandlerFunc(events chan<- any, obj any) {
select {
case events <- obj:
default:
@@ -39,7 +39,7 @@ type clientMock struct {
tcpRoutes []*gatev1alpha2.TCPRoute
tlsRoutes []*gatev1alpha2.TLSRoute
watchChan chan interface{}
watchChan chan any
}
func newClientMock(paths ...string) clientMock {
@@ -224,6 +224,6 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
return nil, false, nil
}
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error) {
return c.watchChan, nil
}
+54 -59
View File
@@ -5,6 +5,7 @@ import (
"crypto/sha256"
"errors"
"fmt"
"maps"
"net"
"os"
"sort"
@@ -62,60 +63,12 @@ func (p *Provider) SetRouterTransform(routerTransform k8s.RouterTransform) {
p.routerTransform = routerTransform
}
func (p *Provider) applyRouterTransform(ctx context.Context, rt *dynamic.Router, route *gatev1alpha2.HTTPRoute) {
if p.routerTransform == nil {
return
}
err := p.routerTransform.Apply(ctx, rt, route.Annotations)
if err != nil {
log.FromContext(ctx).WithError(err).Error("Apply router transform")
}
}
// Entrypoint defines the available entry points.
type Entrypoint struct {
Address string
HasHTTPTLSConf bool
}
func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
// Label selector validation
_, err := labels.Parse(p.LabelSelector)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %q", p.LabelSelector)
}
logger := log.FromContext(ctx)
logger.Infof("label selector is: %q", p.LabelSelector)
withEndpoint := ""
if p.Endpoint != "" {
withEndpoint = fmt.Sprintf(" with endpoint %s", p.Endpoint)
}
var client *clientWrapper
switch {
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
logger.Infof("Creating in-cluster Provider client%s", withEndpoint)
client, err = newInClusterClient(p.Endpoint)
case os.Getenv("KUBECONFIG") != "":
logger.Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
default:
logger.Infof("Creating cluster-external Provider client%s", withEndpoint)
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
}
if err != nil {
return nil, err
}
client.labelSelector = p.LabelSelector
return client, nil
}
// Init the provider.
func (p *Provider) Init() error {
return nil
@@ -195,6 +148,54 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) applyRouterTransform(ctx context.Context, rt *dynamic.Router, route *gatev1alpha2.HTTPRoute) {
if p.routerTransform == nil {
return
}
err := p.routerTransform.Apply(ctx, rt, route.Annotations)
if err != nil {
log.FromContext(ctx).WithError(err).Error("Apply router transform")
}
}
func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
// Label selector validation
_, err := labels.Parse(p.LabelSelector)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %q", p.LabelSelector)
}
logger := log.FromContext(ctx)
logger.Infof("label selector is: %q", p.LabelSelector)
withEndpoint := ""
if p.Endpoint != "" {
withEndpoint = fmt.Sprintf(" with endpoint %s", p.Endpoint)
}
var client *clientWrapper
switch {
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
logger.Infof("Creating in-cluster Provider client%s", withEndpoint)
client, err = newInClusterClient(p.Endpoint)
case os.Getenv("KUBECONFIG") != "":
logger.Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
default:
logger.Infof("Creating cluster-external Provider client%s", withEndpoint)
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
}
if err != nil {
return nil, err
}
client.labelSelector = p.LabelSelector
return client, nil
}
// TODO Handle errors and update resources statuses (gatewayClass, gateway).
func (p *Provider) loadConfigurationFromGateway(ctx context.Context, client Client) *dynamic.Configuration {
logger := log.FromContext(ctx)
@@ -795,9 +796,7 @@ func (p *Provider) gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, li
continue
}
for svcName, svc := range subServices {
conf.HTTP.Services[svcName] = svc
}
maps.Copy(conf.HTTP.Services, subServices)
serviceName := provider.Normalize(routerKey + "-wrr")
conf.HTTP.Services[serviceName] = wrrService
@@ -911,9 +910,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener gatev1alp
continue
}
for svcName, svc := range subServices {
conf.TCP.Services[svcName] = svc
}
maps.Copy(conf.TCP.Services, subServices)
serviceName := fmt.Sprintf("%s-wrr-%d", routerKey, i)
conf.TCP.Services[serviceName] = wrrService
@@ -1058,9 +1055,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener gatev1alp
continue
}
for svcName, svc := range subServices {
conf.TCP.Services[svcName] = svc
}
maps.Copy(conf.TCP.Services, subServices)
serviceName := fmt.Sprintf("%s-wrr-%d", routerKey, i)
conf.TCP.Services[serviceName] = wrrService
@@ -1686,12 +1681,12 @@ func getProtocol(portSpec corev1.ServicePort) string {
return protocol
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan any) chan any {
if throttleDuration == 0 {
return nil
}
// Create a buffered channel to hold the pending event (if we're delaying processing the event due to throttling)
eventsChanBuffered := make(chan interface{}, 1)
eventsChanBuffered := make(chan any, 1)
// Run a goroutine that reads events from eventChan and does a non-blocking write to pendingEvent.
// This guarantees that writing to eventChan will never block,
+53 -53
View File
@@ -36,7 +36,7 @@ const (
// WatchAll starts the watch of the Provider resources and updates the stores.
// The stores can then be accessed via the Get* functions.
type Client interface {
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error)
GetIngresses() []*netv1.Ingress
GetIngressClasses() ([]*netv1.IngressClass, error)
GetService(namespace, name string) (*corev1.Service, bool, error)
@@ -132,7 +132,7 @@ func newClientImpl(clientset kclientset.Interface) *clientWrapper {
}
// WatchAll starts namespace-specific controllers for all relevant kinds.
func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error) {
// Get and store the serverVersion for future use.
serverVersionInfo, err := c.clientset.Discovery().ServerVersion()
if err != nil {
@@ -146,7 +146,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
c.serverVersion = serverVersion
eventCh := make(chan interface{}, 1)
eventCh := make(chan any, 1)
eventHandler := &k8s.ResourceEventHandler{Ev: eventCh}
if len(namespaces) == 0 {
@@ -376,43 +376,6 @@ func (c *clientWrapper) UpdateIngressStatus(src *netv1.Ingress, ingStatus []netv
return nil
}
func (c *clientWrapper) updateIngressStatusOld(src *netv1.Ingress, ingStatus []netv1.IngressLoadBalancerIngress) error {
ing, err := c.factoriesIngress[c.lookupNamespace(src.Namespace)].Networking().V1beta1().Ingresses().Lister().Ingresses(src.Namespace).Get(src.Name)
if err != nil {
return fmt.Errorf("failed to get ingress %s/%s: %w", src.Namespace, src.Name, err)
}
logger := log.WithoutContext().WithField("namespace", ing.Namespace).WithField("ingress", ing.Name)
ingresses, err := convertSlice[netv1.IngressLoadBalancerIngress](ing.Status.LoadBalancer.Ingress)
if err != nil {
return err
}
if isLoadBalancerIngressEquals(ingresses, ingStatus) {
logger.Debug("Skipping ingress status update")
return nil
}
ingressesBeta1, err := convertSlice[netv1beta1.IngressLoadBalancerIngress](ingStatus)
if err != nil {
return err
}
ingCopy := ing.DeepCopy()
ingCopy.Status = netv1beta1.IngressStatus{LoadBalancer: netv1beta1.IngressLoadBalancerStatus{Ingress: ingressesBeta1}}
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
defer cancel()
_, err = c.clientset.NetworkingV1beta1().Ingresses(ingCopy.Namespace).UpdateStatus(ctx, ingCopy, metav1.UpdateOptions{})
if err != nil {
return fmt.Errorf("failed to update ingress status %s/%s: %w", src.Namespace, src.Name, err)
}
logger.Info("Updated ingress status")
return nil
}
// isLoadBalancerIngressEquals returns true if the given slices are equal, false otherwise.
func isLoadBalancerIngressEquals(aSlice, bSlice []netv1.IngressLoadBalancerIngress) bool {
if len(aSlice) != len(bSlice) {
@@ -506,6 +469,48 @@ func (c *clientWrapper) GetIngressClasses() ([]*netv1.IngressClass, error) {
return ics, nil
}
// GetServerVersion returns the cluster server version, or an error.
func (c *clientWrapper) GetServerVersion() *version.Version {
return c.serverVersion
}
func (c *clientWrapper) updateIngressStatusOld(src *netv1.Ingress, ingStatus []netv1.IngressLoadBalancerIngress) error {
ing, err := c.factoriesIngress[c.lookupNamespace(src.Namespace)].Networking().V1beta1().Ingresses().Lister().Ingresses(src.Namespace).Get(src.Name)
if err != nil {
return fmt.Errorf("failed to get ingress %s/%s: %w", src.Namespace, src.Name, err)
}
logger := log.WithoutContext().WithField("namespace", ing.Namespace).WithField("ingress", ing.Name)
ingresses, err := convertSlice[netv1.IngressLoadBalancerIngress](ing.Status.LoadBalancer.Ingress)
if err != nil {
return err
}
if isLoadBalancerIngressEquals(ingresses, ingStatus) {
logger.Debug("Skipping ingress status update")
return nil
}
ingressesBeta1, err := convertSlice[netv1beta1.IngressLoadBalancerIngress](ingStatus)
if err != nil {
return err
}
ingCopy := ing.DeepCopy()
ingCopy.Status = netv1beta1.IngressStatus{LoadBalancer: netv1beta1.IngressLoadBalancerStatus{Ingress: ingressesBeta1}}
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
defer cancel()
_, err = c.clientset.NetworkingV1beta1().Ingresses(ingCopy.Namespace).UpdateStatus(ctx, ingCopy, metav1.UpdateOptions{})
if err != nil {
return fmt.Errorf("failed to update ingress status %s/%s: %w", src.Namespace, src.Name, err)
}
logger.Info("Updated ingress status")
return nil
}
// lookupNamespace returns the lookup namespace key for the given namespace.
// When listening on all namespaces, it returns the client-go identifier ("")
// for all-namespaces. Otherwise, it returns the given namespace.
@@ -519,9 +524,14 @@ func (c *clientWrapper) lookupNamespace(ns string) string {
return ns
}
// GetServerVersion returns the cluster server version, or an error.
func (c *clientWrapper) GetServerVersion() *version.Version {
return c.serverVersion
// isWatchedNamespace checks to ensure that the namespace is being watched before we request
// it to ensure we don't panic by requesting an out-of-watch object.
func (c *clientWrapper) isWatchedNamespace(ns string) bool {
if c.isNamespaceAll {
return true
}
return slices.Contains(c.watchedNamespaces, ns)
}
// translateNotFoundError will translate a "not found" error to a boolean return
@@ -533,16 +543,6 @@ func translateNotFoundError(err error) (bool, error) {
return err == nil, err
}
// isWatchedNamespace checks to ensure that the namespace is being watched before we request
// it to ensure we don't panic by requesting an out-of-watch object.
func (c *clientWrapper) isWatchedNamespace(ns string) bool {
if c.isNamespaceAll {
return true
}
return slices.Contains(c.watchedNamespaces, ns)
}
// IngressClass objects are supported since Kubernetes v1.18.
// See https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class
func supportsIngressClass(serverVersion *version.Version) bool {
@@ -27,7 +27,7 @@ type clientMock struct {
apiEndpointsError error
apiIngressStatusError error
watchChan chan interface{}
watchChan chan any
}
func newClientMock(serverVersion string, paths ...string) clientMock {
@@ -128,7 +128,7 @@ func (c clientMock) GetIngressClasses() ([]*netv1.IngressClass, error) {
return c.ingressClasses, nil
}
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan any, error) {
return c.watchChan, nil
}
+45 -51
View File
@@ -58,17 +58,6 @@ func (p *Provider) SetRouterTransform(routerTransform k8s.RouterTransform) {
p.routerTransform = routerTransform
}
func (p *Provider) applyRouterTransform(ctx context.Context, rt *dynamic.Router, ingress *netv1.Ingress) {
if p.routerTransform == nil {
return
}
err := p.routerTransform.Apply(ctx, rt, ingress.Annotations)
if err != nil {
log.FromContext(ctx).WithError(err).Error("Apply router transform")
}
}
// EndpointIngress holds the endpoint information for the Kubernetes provider.
type EndpointIngress struct {
IP string `description:"IP used for Kubernetes Ingress endpoints." json:"ip,omitempty" toml:"ip,omitempty" yaml:"ip,omitempty"`
@@ -76,42 +65,6 @@ type EndpointIngress struct {
PublishedService string `description:"Published Kubernetes Service to copy status from." json:"publishedService,omitempty" toml:"publishedService,omitempty" yaml:"publishedService,omitempty"`
}
func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
_, err := labels.Parse(p.LabelSelector)
if err != nil {
return nil, fmt.Errorf("invalid ingress label selector: %q", p.LabelSelector)
}
logger := log.FromContext(ctx)
logger.Infof("ingress label selector is: %q", p.LabelSelector)
withEndpoint := ""
if p.Endpoint != "" {
withEndpoint = fmt.Sprintf(" with endpoint %v", p.Endpoint)
}
var cl *clientWrapper
switch {
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
logger.Infof("Creating in-cluster Provider client%s", withEndpoint)
cl, err = newInClusterClient(p.Endpoint)
case os.Getenv("KUBECONFIG") != "":
logger.Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
cl, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
default:
logger.Infof("Creating cluster-external Provider client%s", withEndpoint)
cl, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
}
if err != nil {
return nil, err
}
cl.ingressLabelSelector = p.LabelSelector
return cl, nil
}
// Init the provider.
func (p *Provider) Init() error {
return nil
@@ -199,6 +152,47 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) applyRouterTransform(ctx context.Context, rt *dynamic.Router, ingress *netv1.Ingress) {
if p.routerTransform == nil {
return
}
err := p.routerTransform.Apply(ctx, rt, ingress.Annotations)
if err != nil {
log.FromContext(ctx).WithError(err).Error("Apply router transform")
}
}
func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
_, err := labels.Parse(p.LabelSelector)
if err != nil {
return nil, fmt.Errorf("invalid ingress label selector: %q", p.LabelSelector)
}
logger := log.FromContext(ctx)
logger.Debugf("Creating in-cluster Provider client")
var client *clientWrapper
switch {
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
client, err = newInClusterClient(p.Endpoint)
case os.Getenv("KUBECONFIG") != "":
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
default:
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
}
if err != nil {
return nil, err
}
client.ingressLabelSelector = p.LabelSelector
return client, nil
}
func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Client) *dynamic.Configuration {
conf := &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
@@ -404,8 +398,8 @@ func (p *Provider) updateIngressStatus(ing *netv1.Ingress, k8sClient Client) err
}
if exists && service.Status.LoadBalancer.Ingress == nil {
// service exists, but has no Load Balancer status
log.Debugf("Skipping updating Ingress %s/%s due to service %s having no status set", ing.Namespace, ing.Name, p.IngressEndpoint.PublishedService)
// service exists but has no Load Balancer status
log.WithoutContext().Debugf("Skipping updating Ingress %s/%s due to service %s having no status set", ing.Namespace, ing.Name, p.IngressEndpoint.PublishedService)
return nil
}
@@ -715,13 +709,13 @@ func loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *Rout
return rt
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan any) chan any {
if throttleDuration == 0 {
return nil
}
// Create a buffered channel to hold the pending event (if we're delaying processing the event due to throttling).
eventsChanBuffered := make(chan interface{}, 1)
eventsChanBuffered := make(chan any, 1)
// Run a goroutine that reads events from eventChan and does a
// non-blocking write to pendingEvent. This guarantees that writing to
+6 -6
View File
@@ -7,38 +7,38 @@ import (
// ResourceEventHandler handles Add, Update or Delete Events for resources.
type ResourceEventHandler struct {
Ev chan<- interface{}
Ev chan<- any
}
// OnAdd is called on Add Events.
func (reh *ResourceEventHandler) OnAdd(obj interface{}, _ bool) {
func (reh *ResourceEventHandler) OnAdd(obj any, _ bool) {
eventHandlerFunc(reh.Ev, obj)
}
// OnUpdate is called on Update Events.
// Ignores useless changes.
func (reh *ResourceEventHandler) OnUpdate(oldObj, newObj interface{}) {
func (reh *ResourceEventHandler) OnUpdate(oldObj, newObj any) {
if objChanged(oldObj, newObj) {
eventHandlerFunc(reh.Ev, newObj)
}
}
// OnDelete is called on Delete Events.
func (reh *ResourceEventHandler) OnDelete(obj interface{}) {
func (reh *ResourceEventHandler) OnDelete(obj any) {
eventHandlerFunc(reh.Ev, obj)
}
// eventHandlerFunc will pass the obj on to the events channel or drop it.
// This is so passing the events along won't block in the case of high volume.
// The events are only used for signaling anyway so dropping a few is ok.
func eventHandlerFunc(events chan<- interface{}, obj interface{}) {
func eventHandlerFunc(events chan<- any, obj any) {
select {
case events <- obj:
default:
}
}
func objChanged(oldObj, newObj interface{}) bool {
func objChanged(oldObj, newObj any) bool {
if oldObj == nil || newObj == nil {
return true
}
@@ -12,8 +12,8 @@ import (
func Test_detectChanges(t *testing.T) {
tests := []struct {
name string
oldObj interface{}
newObj interface{}
oldObj any
newObj any
want bool
}{
{
+2 -4
View File
@@ -386,8 +386,7 @@ func processPorts(app marathon.Application, task marathon.Task, serverPort strin
}
}
if strings.HasPrefix(serverPort, "name:") {
name := strings.TrimPrefix(serverPort, "name:")
if name, ok := strings.CutPrefix(serverPort, "name:"); ok {
port := retrieveNamedPort(app, name)
if port == 0 {
@@ -403,8 +402,7 @@ func processPorts(app marathon.Application, task marathon.Task, serverPort strin
}
portIndex := 0
if strings.HasPrefix(serverPort, "index:") {
indexString := strings.TrimPrefix(serverPort, "index:")
if indexString, ok := strings.CutPrefix(serverPort, "index:"); ok {
index, err := strconv.Atoi(indexString)
if err != nil {
return 0, err
+2 -2
View File
@@ -87,8 +87,8 @@ type Basic struct {
// Init the provider.
func (p *Provider) Init() error {
fm := template.FuncMap{
"strsToItfs": func(values []string) []interface{} {
var r []interface{}
"strsToItfs": func(values []string) []any {
var r []any
for _, v := range values {
r = append(r, v)
}
+3 -3
View File
@@ -98,7 +98,7 @@ func (rc *readinessChecker) Do(task marathon.Task, app marathon.Application) boo
// An unparseable start time should never occur; if it does, we assume the
// problem should be surfaced as quickly as possible, which is easiest if
// we shun the task from rotation.
log.Warnf("Failed to parse start-time %s of task %s from application %s: %s (assuming unready)", task.StartedAt, task.ID, app.ID, err)
log.WithoutContext().Warnf("Failed to parse start-time %s of task %s from application %s: %s (assuming unready)", task.StartedAt, task.ID, app.ID, err)
return false
}
@@ -115,8 +115,8 @@ func (rc *readinessChecker) Do(task marathon.Task, app marathon.Application) boo
return true
}
func (rc *readinessChecker) tracef(format string, args ...interface{}) {
func (rc *readinessChecker) tracef(format string, args ...any) {
if rc.traceLogging {
log.Debugf(readinessLogHeader+format, args...)
log.WithoutContext().Debugf(readinessLogHeader+format, args...)
}
}
+11 -11
View File
@@ -82,17 +82,6 @@ func (p *Provider) Init() error {
return nil
}
func (p *Provider) createClient(ctx context.Context) (rancher.Client, error) {
metadataServiceURL := fmt.Sprintf("http://rancher-metadata.rancher.internal/%s", p.Prefix)
client, err := rancher.NewClientAndWait(metadataServiceURL)
if err != nil {
log.FromContext(ctx).Errorf("Failed to create Rancher metadata service client: %v", err)
return nil, err
}
return client, nil
}
// Provide allows the rancher provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
pool.GoCtx(func(routineCtx context.Context) {
@@ -150,6 +139,17 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
return nil
}
func (p *Provider) createClient(ctx context.Context) (rancher.Client, error) {
metadataServiceURL := fmt.Sprintf("http://rancher-metadata.rancher.internal/%s", p.Prefix)
client, err := rancher.NewClientAndWait(metadataServiceURL)
if err != nil {
log.FromContext(ctx).Errorf("Failed to create Rancher metadata service client: %v", err)
return nil, err
}
return client, nil
}
func (p *Provider) intervalPoll(ctx context.Context, client rancher.Client, updateConfiguration func(string)) {
ticker := time.NewTicker(time.Duration(p.RefreshSeconds) * time.Second)
defer ticker.Stop()
+8 -8
View File
@@ -20,11 +20,11 @@ const (
// Anonymize redacts the configuration fields that do not have an export=true struct tag.
// It returns the resulting marshaled configuration.
func Anonymize(baseConfig interface{}) (string, error) {
func Anonymize(baseConfig any) (string, error) {
return anonymize(baseConfig, false)
}
func anonymize(baseConfig interface{}, indent bool) (string, error) {
func anonymize(baseConfig any, indent bool) (string, error) {
conf, err := do(baseConfig, tagExport, true, indent)
if err != nil {
return "", err
@@ -34,17 +34,17 @@ func anonymize(baseConfig interface{}, indent bool) (string, error) {
// RemoveCredentials redacts the configuration fields that have a loggable=false struct tag.
// It returns the resulting marshaled configuration.
func RemoveCredentials(baseConfig interface{}) (string, error) {
func RemoveCredentials(baseConfig any) (string, error) {
return removeCredentials(baseConfig, false)
}
func removeCredentials(baseConfig interface{}, indent bool) (string, error) {
func removeCredentials(baseConfig any, indent bool) (string, error) {
return do(baseConfig, tagLoggable, false, indent)
}
// do marshals the given configuration, while redacting some of the fields
// respectively to the given tag.
func do(baseConfig interface{}, tag string, redactByDefault, indent bool) (string, error) {
func do(baseConfig any, tag string, redactByDefault, indent bool) (string, error) {
anomConfig, err := copystructure.Copy(baseConfig)
if err != nil {
return "", err
@@ -70,7 +70,7 @@ func doOnJSON(input string) string {
}
func doOnStruct(field reflect.Value, tag string, redactByDefault bool) error {
if field.Type().AssignableTo(reflect.TypeOf(dynamic.PluginConf{})) {
if field.Type().AssignableTo(reflect.TypeFor[dynamic.PluginConf]()) {
resetPlugin(field)
return nil
}
@@ -164,7 +164,7 @@ func reset(field reflect.Value, name string) error {
}
case reflect.String:
if field.String() != "" {
if field.Type().AssignableTo(reflect.TypeOf(tls.FileOrContent(""))) {
if field.Type().AssignableTo(reflect.TypeFor[tls.FileOrContent]()) {
field.Set(reflect.ValueOf(tls.FileOrContent(maskShort)))
} else {
field.Set(reflect.ValueOf(maskShort))
@@ -211,7 +211,7 @@ func isExported(f reflect.StructField) bool {
return true
}
func marshal(anomConfig interface{}, indent bool) ([]byte, error) {
func marshal(anomConfig any, indent bool) ([]byte, error) {
if indent {
return json.MarshalIndent(anomConfig, "", " ")
}
+4 -5
View File
@@ -2,6 +2,7 @@ package rules
import (
"fmt"
"slices"
"strings"
"github.com/vulcand/predicate"
@@ -28,7 +29,7 @@ type Tree struct {
// NewParser constructs a parser for the given matchers.
func NewParser(matchers []string) (predicate.Parser, error) {
parserFuncs := make(map[string]interface{})
parserFuncs := make(map[string]any)
for _, matcherName := range matchers {
fn := func(value ...string) TreeBuilder {
@@ -104,10 +105,8 @@ func (tree *Tree) ParseMatchers(matchers []string) []string {
case and, or:
return append(tree.RuleLeft.ParseMatchers(matchers), tree.RuleRight.ParseMatchers(matchers)...)
default:
for _, matcher := range matchers {
if tree.Matcher == matcher {
return lower(tree.Value)
}
if slices.Contains(matchers, tree.Matcher) {
return lower(tree.Value)
}
return nil
+2 -2
View File
@@ -49,7 +49,7 @@ func Go(goroutine func()) {
}
// GoWithRecover starts a recoverable goroutine using given customRecover() function.
func GoWithRecover(goroutine func(), customRecover func(err interface{})) {
func GoWithRecover(goroutine func(), customRecover func(err any)) {
go func() {
defer func() {
if err := recover(); err != nil {
@@ -60,7 +60,7 @@ func GoWithRecover(goroutine func(), customRecover func(err interface{})) {
}()
}
func defaultRecoverGoroutine(err interface{}) {
func defaultRecoverGoroutine(err any) {
logger := log.WithoutContext()
logger.Errorf("Error in Go routine: %s", err)
logger.Errorf("Stack: %s", debug.Stack())
+1
View File
@@ -29,6 +29,7 @@ func TestNewPoolContext(t *testing.T) {
type fakeRoutine struct {
sync.Mutex
started bool
startSig chan bool
}
+4 -4
View File
@@ -6,24 +6,24 @@ import (
// Safe contains a thread-safe value.
type Safe struct {
value interface{}
value any
lock sync.RWMutex
}
// New create a new Safe instance given a value.
func New(value interface{}) *Safe {
func New(value any) *Safe {
return &Safe{value: value, lock: sync.RWMutex{}}
}
// Get returns the value.
func (s *Safe) Get() interface{} {
func (s *Safe) Get() any {
s.lock.RLock()
defer s.lock.RUnlock()
return s.value
}
// Set sets a new value.
func (s *Safe) Set(value interface{}) {
func (s *Safe) Set(value any) {
s.lock.Lock()
defer s.lock.Unlock()
s.value = value

Some files were not shown because too many files have changed in this diff Show More