mirror of
https://github.com/traefik/traefik
synced 2026-02-03 08:50:32 +00:00
Upgrade golangci-lint
This commit is contained in:
@@ -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
@@ -15,7 +15,7 @@ func init() {
|
||||
expvar.Publish("Goroutines2", expvar.Func(goroutines))
|
||||
}
|
||||
|
||||
func goroutines() interface{} {
|
||||
func goroutines() any {
|
||||
return runtime.NumGoroutine()
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -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()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
type entryPointRepresentation struct {
|
||||
*static.EntryPoint
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
package static
|
||||
|
||||
// PluginConf holds the plugin configuration.
|
||||
type PluginConf map[string]interface{}
|
||||
type PluginConf map[string]any
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
|
||||
@@ -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
|
||||
}),
|
||||
|
||||
@@ -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
|
||||
}))
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ func NewEntryPoint(ctx context.Context, t *tracing.Tracing, entryPointName strin
|
||||
|
||||
type entryPointMiddleware struct {
|
||||
*tracing.Tracing
|
||||
|
||||
entryPoint string
|
||||
next http.Handler
|
||||
}
|
||||
|
||||
@@ -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": "",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -22,6 +22,7 @@ func newStatusCodeRecoder(rw http.ResponseWriter, status int) statusCodeRecoder
|
||||
|
||||
type statusCodeWithoutCloseNotify struct {
|
||||
http.ResponseWriter
|
||||
|
||||
status int
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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), "-", "_")
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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,5 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package acme
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}{
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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())
|
||||
|
||||
@@ -29,6 +29,7 @@ func TestNewPoolContext(t *testing.T) {
|
||||
|
||||
type fakeRoutine struct {
|
||||
sync.Mutex
|
||||
|
||||
started bool
|
||||
startSig chan bool
|
||||
}
|
||||
|
||||
+4
-4
@@ -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
Reference in New Issue
Block a user