WeightedRoundRobin load balancer
Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
This commit is contained in:
parent
84de444325
commit
6fed76a687
44 changed files with 1612 additions and 833 deletions
|
@ -0,0 +1,22 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 10
|
||||
- name: whoami2
|
||||
port: 8080
|
||||
weight: 0
|
||||
|
|
@ -3,7 +3,6 @@ package crd
|
|||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
@ -16,7 +15,6 @@ import (
|
|||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/job"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/v2/pkg/safe"
|
||||
"github.com/containous/traefik/v2/pkg/tls"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
@ -136,159 +134,22 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkStringQuoteValidity(value string) error {
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return err
|
||||
}
|
||||
|
||||
func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) {
|
||||
service, exists, err := client.GetService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) *dynamic.Configuration {
|
||||
tlsConfigs := make(map[string]*tls.CertAndStores)
|
||||
conf := &dynamic.Configuration{
|
||||
HTTP: p.loadIngressRouteConfiguration(ctx, client, tlsConfigs),
|
||||
TCP: p.loadIngressRouteTCPConfiguration(ctx, client, tlsConfigs),
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: getTLSConfig(tlsConfigs),
|
||||
Options: buildTLSOptions(ctx, client),
|
||||
},
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
}
|
||||
|
||||
var portSpec *corev1.ServicePort
|
||||
for _, p := range service.Spec.Ports {
|
||||
if svc.Port == p.Port {
|
||||
portSpec = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if portSpec == nil {
|
||||
return nil, errors.New("service port not found")
|
||||
}
|
||||
|
||||
var servers []dynamic.TCPServer
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
servers = append(servers, dynamic.TCPServer{
|
||||
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, dynamic.TCPServer{
|
||||
Address: fmt.Sprintf("%s:%d", addr.IP, port),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynamic.Server, error) {
|
||||
strategy := svc.Strategy
|
||||
if strategy == "" {
|
||||
strategy = "RoundRobin"
|
||||
}
|
||||
if strategy != "RoundRobin" {
|
||||
return nil, fmt.Errorf("load balancing strategy %v is not supported", strategy)
|
||||
}
|
||||
|
||||
service, exists, err := client.GetService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
var portSpec *corev1.ServicePort
|
||||
for _, p := range service.Spec.Ports {
|
||||
if svc.Port == p.Port {
|
||||
portSpec = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if portSpec == nil {
|
||||
return nil, errors.New("service port not found")
|
||||
}
|
||||
|
||||
var servers []dynamic.Server
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
switch svc.Scheme {
|
||||
case "http", "https", "h2c":
|
||||
protocol = svc.Scheme
|
||||
case "":
|
||||
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid scheme %q specified", svc.Scheme)
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s:%d", protocol, addr.IP, port),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
return conf
|
||||
}
|
||||
|
||||
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
|
||||
|
@ -338,250 +199,9 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
|||
return tlsOptions
|
||||
}
|
||||
|
||||
func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.HTTPConfiguration {
|
||||
conf := &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
}
|
||||
|
||||
for _, ingressRoute := range client.GetIngressRoutes() {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace)))
|
||||
|
||||
// TODO keep the name ingressClass?
|
||||
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := getTLSHTTP(ctx, ingressRoute, client, tlsConfigs)
|
||||
if err != nil {
|
||||
logger.Errorf("Error configuring TLS: %v", err)
|
||||
}
|
||||
|
||||
ingressName := ingressRoute.Name
|
||||
if len(ingressName) == 0 {
|
||||
ingressName = ingressRoute.GenerateName
|
||||
}
|
||||
|
||||
for _, route := range ingressRoute.Spec.Routes {
|
||||
if route.Kind != "Rule" {
|
||||
logger.Errorf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(route.Match) == 0 {
|
||||
logger.Errorf("Empty match rule")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||
continue
|
||||
}
|
||||
|
||||
var allServers []dynamic.Server
|
||||
for _, service := range route.Services {
|
||||
servers, err := loadServers(client, ingressRoute.Namespace, service)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("serviceName", service.Name).
|
||||
WithField("servicePort", service.Port).
|
||||
Errorf("Cannot create service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
allServers = append(allServers, servers...)
|
||||
}
|
||||
|
||||
var mds []string
|
||||
for _, mi := range route.Middlewares {
|
||||
if strings.Contains(mi.Name, "@") {
|
||||
if len(mi.Namespace) > 0 {
|
||||
logger.
|
||||
WithField(log.MiddlewareName, mi.Name).
|
||||
Warnf("namespace %q is ignored in cross-provider context", mi.Namespace)
|
||||
}
|
||||
mds = append(mds, mi.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
ns := mi.Namespace
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
mds = append(mds, makeID(ns, mi.Name))
|
||||
}
|
||||
|
||||
key, err := makeServiceKey(route.Match, ingressName)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := makeID(ingressRoute.Namespace, key)
|
||||
|
||||
conf.Routers[serviceName] = &dynamic.Router{
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
|
||||
if ingressRoute.Spec.TLS != nil {
|
||||
tlsConf := &dynamic.RouterTLSConfig{
|
||||
CertResolver: ingressRoute.Spec.TLS.CertResolver,
|
||||
}
|
||||
|
||||
if ingressRoute.Spec.TLS.Options != nil && len(ingressRoute.Spec.TLS.Options.Name) > 0 {
|
||||
tlsOptionsName := ingressRoute.Spec.TLS.Options.Name
|
||||
// Is a Kubernetes CRD reference, (i.e. not a cross-provider reference)
|
||||
ns := ingressRoute.Spec.TLS.Options.Namespace
|
||||
if !strings.Contains(tlsOptionsName, "@") {
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||
} else if len(ns) > 0 {
|
||||
logger.
|
||||
WithField("TLSoptions", ingressRoute.Spec.TLS.Options.Name).
|
||||
Warnf("namespace %q is ignored in cross-provider context", ns)
|
||||
}
|
||||
|
||||
tlsConf.Options = tlsOptionsName
|
||||
}
|
||||
conf.Routers[serviceName].TLS = tlsConf
|
||||
}
|
||||
|
||||
conf.Services[serviceName] = &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
Servers: allServers,
|
||||
// TODO: support other strategies.
|
||||
PassHostHeader: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.TCPConfiguration {
|
||||
conf := &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
}
|
||||
|
||||
for _, ingressRouteTCP := range client.GetIngressRouteTCPs() {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRouteTCP.Name), log.Str("namespace", ingressRouteTCP.Namespace)))
|
||||
|
||||
if !shouldProcessIngress(p.IngressClass, ingressRouteTCP.Annotations[annotationKubernetesIngressClass]) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS != nil && !ingressRouteTCP.Spec.TLS.Passthrough {
|
||||
err := getTLSTCP(ctx, ingressRouteTCP, client, tlsConfigs)
|
||||
if err != nil {
|
||||
logger.Errorf("Error configuring TLS: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
ingressName := ingressRouteTCP.Name
|
||||
if len(ingressName) == 0 {
|
||||
ingressName = ingressRouteTCP.GenerateName
|
||||
}
|
||||
|
||||
for _, route := range ingressRouteTCP.Spec.Routes {
|
||||
if len(route.Match) == 0 {
|
||||
logger.Errorf("Empty match rule")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||
continue
|
||||
}
|
||||
|
||||
var allServers []dynamic.TCPServer
|
||||
for _, service := range route.Services {
|
||||
servers, err := loadTCPServers(client, ingressRouteTCP.Namespace, service)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("serviceName", service.Name).
|
||||
WithField("servicePort", service.Port).
|
||||
Errorf("Cannot create service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
allServers = append(allServers, servers...)
|
||||
}
|
||||
|
||||
key, e := makeServiceKey(route.Match, ingressName)
|
||||
if e != nil {
|
||||
logger.Error(e)
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := makeID(ingressRouteTCP.Namespace, key)
|
||||
conf.Routers[serviceName] = &dynamic.TCPRouter{
|
||||
EntryPoints: ingressRouteTCP.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS != nil {
|
||||
conf.Routers[serviceName].TLS = &dynamic.RouterTCPTLSConfig{
|
||||
Passthrough: ingressRouteTCP.Spec.TLS.Passthrough,
|
||||
CertResolver: ingressRouteTCP.Spec.TLS.CertResolver,
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 {
|
||||
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
|
||||
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
|
||||
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
|
||||
if !strings.Contains(tlsOptionsName, "@") {
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRouteTCP.Namespace
|
||||
}
|
||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||
} else if len(ns) > 0 {
|
||||
logger.
|
||||
WithField("TLSoptions", ingressRouteTCP.Spec.TLS.Options.Name).
|
||||
Warnf("namespace %q is ignored in cross-provider context", ns)
|
||||
}
|
||||
|
||||
conf.Routers[serviceName].TLS.Options = tlsOptionsName
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
conf.Services[serviceName] = &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: allServers,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) *dynamic.Configuration {
|
||||
tlsConfigs := make(map[string]*tls.CertAndStores)
|
||||
conf := &dynamic.Configuration{
|
||||
HTTP: p.loadIngressRouteConfiguration(ctx, client, tlsConfigs),
|
||||
TCP: p.loadIngressRouteTCPConfiguration(ctx, client, tlsConfigs),
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: getTLSConfig(tlsConfigs),
|
||||
Options: buildTLSOptions(ctx, client),
|
||||
},
|
||||
}
|
||||
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
}
|
||||
|
||||
return conf
|
||||
func checkStringQuoteValidity(value string) error {
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return err
|
||||
}
|
||||
|
||||
func makeServiceKey(rule, ingressName string) (string, error) {
|
||||
|
@ -608,50 +228,6 @@ func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bo
|
|||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
|
||||
}
|
||||
|
||||
func getTLSHTTP(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
||||
if ingressRoute.Spec.TLS == nil {
|
||||
return nil
|
||||
}
|
||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||
log.FromContext(ctx).Debugf("Skipping TLS sub-section: No secret name provided")
|
||||
return nil
|
||||
}
|
||||
|
||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfigs[configKey] = tlsConf
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTLSTCP(ctx context.Context, ingressRoute *v1alpha1.IngressRouteTCP, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
||||
if ingressRoute.Spec.TLS == nil {
|
||||
return nil
|
||||
}
|
||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||
log.FromContext(ctx).Debugf("Skipping TLS sub-section for TCP: No secret name provided")
|
||||
return nil
|
||||
}
|
||||
|
||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfigs[configKey] = tlsConf
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTLS(k8sClient Client, secretName, namespace string) (*tls.CertAndStores, error) {
|
||||
secret, exists, err := k8sClient.GetSecret(namespace, secretName)
|
||||
if err != nil {
|
||||
|
|
274
pkg/provider/kubernetes/crd/kubernetes_http.go
Normal file
274
pkg/provider/kubernetes/crd/kubernetes_http.go
Normal file
|
@ -0,0 +1,274 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/v2/pkg/tls"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.HTTPConfiguration {
|
||||
conf := &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
}
|
||||
|
||||
for _, ingressRoute := range client.GetIngressRoutes() {
|
||||
ctxRt := log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace))
|
||||
logger := log.FromContext(ctxRt)
|
||||
|
||||
// TODO keep the name ingressClass?
|
||||
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := getTLSHTTP(ctx, ingressRoute, client, tlsConfigs)
|
||||
if err != nil {
|
||||
logger.Errorf("Error configuring TLS: %v", err)
|
||||
}
|
||||
|
||||
ingressName := ingressRoute.Name
|
||||
if len(ingressName) == 0 {
|
||||
ingressName = ingressRoute.GenerateName
|
||||
}
|
||||
|
||||
for _, route := range ingressRoute.Spec.Routes {
|
||||
if route.Kind != "Rule" {
|
||||
logger.Errorf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(route.Match) == 0 {
|
||||
logger.Errorf("Empty match rule")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||
continue
|
||||
}
|
||||
|
||||
key, err := makeServiceKey(route.Match, ingressName)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := makeID(ingressRoute.Namespace, key)
|
||||
|
||||
for _, service := range route.Services {
|
||||
balancerServerHTTP, err := createLoadBalancerServerHTTP(client, ingressRoute, service)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("serviceName", service.Name).
|
||||
WithField("servicePort", service.Port).
|
||||
Errorf("Cannot create service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(route.Services) == 1 {
|
||||
conf.Services[serviceName] = balancerServerHTTP
|
||||
break
|
||||
}
|
||||
|
||||
serviceKey := fmt.Sprintf("%s-%s-%d", serviceName, service.Name, service.Port)
|
||||
conf.Services[serviceKey] = balancerServerHTTP
|
||||
|
||||
srv := dynamic.WRRService{Name: serviceKey}
|
||||
srv.SetDefaults()
|
||||
if service.Weight != nil {
|
||||
srv.Weight = service.Weight
|
||||
}
|
||||
|
||||
if conf.Services[serviceName] == nil {
|
||||
conf.Services[serviceName] = &dynamic.Service{Weighted: &dynamic.WeightedRoundRobin{}}
|
||||
}
|
||||
conf.Services[serviceName].Weighted.Services = append(conf.Services[serviceName].Weighted.Services, srv)
|
||||
}
|
||||
|
||||
var mds []string
|
||||
for _, mi := range route.Middlewares {
|
||||
if strings.Contains(mi.Name, "@") {
|
||||
if len(mi.Namespace) > 0 {
|
||||
logger.
|
||||
WithField(log.MiddlewareName, mi.Name).
|
||||
Warnf("namespace %q is ignored in cross-provider context", mi.Namespace)
|
||||
}
|
||||
mds = append(mds, mi.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
ns := mi.Namespace
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
mds = append(mds, makeID(ns, mi.Name))
|
||||
}
|
||||
|
||||
conf.Routers[serviceName] = &dynamic.Router{
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
|
||||
if ingressRoute.Spec.TLS != nil {
|
||||
tlsConf := &dynamic.RouterTLSConfig{
|
||||
CertResolver: ingressRoute.Spec.TLS.CertResolver,
|
||||
}
|
||||
|
||||
if ingressRoute.Spec.TLS.Options != nil && len(ingressRoute.Spec.TLS.Options.Name) > 0 {
|
||||
tlsOptionsName := ingressRoute.Spec.TLS.Options.Name
|
||||
// Is a Kubernetes CRD reference, (i.e. not a cross-provider reference)
|
||||
ns := ingressRoute.Spec.TLS.Options.Namespace
|
||||
if !strings.Contains(tlsOptionsName, "@") {
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||
} else if len(ns) > 0 {
|
||||
logger.
|
||||
WithField("TLSoptions", ingressRoute.Spec.TLS.Options.Name).
|
||||
Warnf("namespace %q is ignored in cross-provider context", ns)
|
||||
}
|
||||
|
||||
tlsConf.Options = tlsOptionsName
|
||||
}
|
||||
conf.Routers[serviceName].TLS = tlsConf
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func createLoadBalancerServerHTTP(client Client, ingressRoute *v1alpha1.IngressRoute, service v1alpha1.Service) (*dynamic.Service, error) {
|
||||
servers, err := loadServers(client, ingressRoute.Namespace, service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dynamic.Service{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: servers,
|
||||
// TODO: support other strategies.
|
||||
PassHostHeader: true,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynamic.Server, error) {
|
||||
strategy := svc.Strategy
|
||||
if strategy == "" {
|
||||
strategy = "RoundRobin"
|
||||
}
|
||||
if strategy != "RoundRobin" {
|
||||
return nil, fmt.Errorf("load balancing strategy %v is not supported", strategy)
|
||||
}
|
||||
|
||||
service, exists, err := client.GetService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
var portSpec *corev1.ServicePort
|
||||
for _, p := range service.Spec.Ports {
|
||||
if svc.Port == p.Port {
|
||||
portSpec = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if portSpec == nil {
|
||||
return nil, errors.New("service port not found")
|
||||
}
|
||||
|
||||
var servers []dynamic.Server
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
switch svc.Scheme {
|
||||
case "http", "https", "h2c":
|
||||
protocol = svc.Scheme
|
||||
case "":
|
||||
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid scheme %q specified", svc.Scheme)
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s:%d", protocol, addr.IP, port),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func getTLSHTTP(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
||||
if ingressRoute.Spec.TLS == nil {
|
||||
return nil
|
||||
}
|
||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||
log.FromContext(ctx).Debugf("No secret name provided")
|
||||
return nil
|
||||
}
|
||||
|
||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfigs[configKey] = tlsConf
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
201
pkg/provider/kubernetes/crd/kubernetes_tcp.go
Normal file
201
pkg/provider/kubernetes/crd/kubernetes_tcp.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/v2/pkg/tls"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.TCPConfiguration {
|
||||
conf := &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
}
|
||||
|
||||
for _, ingressRouteTCP := range client.GetIngressRouteTCPs() {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRouteTCP.Name), log.Str("namespace", ingressRouteTCP.Namespace)))
|
||||
|
||||
if !shouldProcessIngress(p.IngressClass, ingressRouteTCP.Annotations[annotationKubernetesIngressClass]) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS != nil && !ingressRouteTCP.Spec.TLS.Passthrough {
|
||||
err := getTLSTCP(ctx, ingressRouteTCP, client, tlsConfigs)
|
||||
if err != nil {
|
||||
logger.Errorf("Error configuring TLS: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
ingressName := ingressRouteTCP.Name
|
||||
if len(ingressName) == 0 {
|
||||
ingressName = ingressRouteTCP.GenerateName
|
||||
}
|
||||
|
||||
for _, route := range ingressRouteTCP.Spec.Routes {
|
||||
if len(route.Match) == 0 {
|
||||
logger.Errorf("Empty match rule")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||
continue
|
||||
}
|
||||
|
||||
var allServers []dynamic.TCPServer
|
||||
for _, service := range route.Services {
|
||||
servers, err := loadTCPServers(client, ingressRouteTCP.Namespace, service)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("serviceName", service.Name).
|
||||
WithField("servicePort", service.Port).
|
||||
Errorf("Cannot create service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
allServers = append(allServers, servers...)
|
||||
}
|
||||
|
||||
key, e := makeServiceKey(route.Match, ingressName)
|
||||
if e != nil {
|
||||
logger.Error(e)
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := makeID(ingressRouteTCP.Namespace, key)
|
||||
conf.Routers[serviceName] = &dynamic.TCPRouter{
|
||||
EntryPoints: ingressRouteTCP.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS != nil {
|
||||
conf.Routers[serviceName].TLS = &dynamic.RouterTCPTLSConfig{
|
||||
Passthrough: ingressRouteTCP.Spec.TLS.Passthrough,
|
||||
CertResolver: ingressRouteTCP.Spec.TLS.CertResolver,
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 {
|
||||
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
|
||||
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
|
||||
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
|
||||
if !strings.Contains(tlsOptionsName, "@") {
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRouteTCP.Namespace
|
||||
}
|
||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||
} else if len(ns) > 0 {
|
||||
logger.
|
||||
WithField("TLSoptions", ingressRouteTCP.Spec.TLS.Options.Name).
|
||||
Warnf("namespace %q is ignored in cross-provider context", ns)
|
||||
}
|
||||
|
||||
conf.Routers[serviceName].TLS.Options = tlsOptionsName
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
conf.Services[serviceName] = &dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||
Servers: allServers,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) {
|
||||
service, exists, err := client.GetService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
var portSpec *corev1.ServicePort
|
||||
for _, p := range service.Spec.Ports {
|
||||
if svc.Port == p.Port {
|
||||
portSpec = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if portSpec == nil {
|
||||
return nil, errors.New("service port not found")
|
||||
}
|
||||
|
||||
var servers []dynamic.TCPServer
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
servers = append(servers, dynamic.TCPServer{
|
||||
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, dynamic.TCPServer{
|
||||
Address: fmt.Sprintf("%s:%d", addr.IP, port),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func getTLSTCP(ctx context.Context, ingressRoute *v1alpha1.IngressRouteTCP, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
||||
if ingressRoute.Spec.TLS == nil {
|
||||
return nil
|
||||
}
|
||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||
log.FromContext(ctx).Debugf("No secret name provided")
|
||||
return nil
|
||||
}
|
||||
|
||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfigs[configKey] = tlsConf
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -12,6 +12,8 @@ import (
|
|||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
func Int(v int) *int { return &v }
|
||||
|
||||
func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -671,7 +673,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -720,7 +722,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test2.route-23c7f4c450289ee29016": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -770,7 +772,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test2.route-23c7f4c450289ee29016": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -812,7 +814,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -825,7 +827,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"default/test.route-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -843,7 +845,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
desc: "One ingress Route with two different services, their servers will merge",
|
||||
desc: "One ingress Route with two different services",
|
||||
paths: []string{"services.yml", "with_two_services.yml"},
|
||||
expected: &dynamic.Configuration{
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
|
@ -863,7 +865,21 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default/test.route-77c62dfe9517144aeeaa-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
{
|
||||
Name: "default/test.route-77c62dfe9517144aeeaa-whoami2-8080",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default/test.route-77c62dfe9517144aeeaa-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -871,6 +887,77 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
"default/test.route-77c62dfe9517144aeeaa-whoami2-8080": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One ingress Route with two different services, with weights",
|
||||
paths: []string{"services.yml", "with_two_services_weight.yml"},
|
||||
expected: &dynamic.Configuration{
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default/test.route-77c62dfe9517144aeeaa": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.route-77c62dfe9517144aeeaa",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-77c62dfe9517144aeeaa": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default/test.route-77c62dfe9517144aeeaa-whoami-80",
|
||||
Weight: Int(10),
|
||||
},
|
||||
{
|
||||
Name: "default/test.route-77c62dfe9517144aeeaa-whoami2-8080",
|
||||
Weight: Int(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default/test.route-77c62dfe9517144aeeaa-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
"default/test.route-77c62dfe9517144aeeaa-whoami2-8080": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
|
@ -981,7 +1068,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1039,7 +1126,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1097,7 +1184,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1154,7 +1241,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1200,7 +1287,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1246,7 +1333,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1284,7 +1371,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1321,7 +1408,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.5:8443",
|
||||
|
@ -1358,7 +1445,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.7:8443",
|
||||
|
|
|
@ -49,6 +49,7 @@ type Service struct {
|
|||
Scheme string `json:"scheme,omitempty"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
Weight *int `json:"weight,omitempty"`
|
||||
}
|
||||
|
||||
// MiddlewareRef is a ref to the Middleware resources.
|
||||
|
|
|
@ -395,6 +395,11 @@ func (in *Service) DeepCopyInto(out *Service) {
|
|||
*out = new(HealthCheck)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Weight != nil {
|
||||
in, out := &in.Weight, &out.Weight
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ func loadService(client Client, namespace string, backend v1beta1.IngressBackend
|
|||
}
|
||||
|
||||
return &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: servers,
|
||||
PassHostHeader: true,
|
||||
},
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -118,7 +118,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -148,7 +148,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -177,7 +177,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/example-com/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -208,7 +208,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -242,7 +242,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -317,7 +317,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -362,7 +362,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -375,7 +375,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"testing/service2/8082": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -428,7 +428,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-backend": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -458,7 +458,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -488,7 +488,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -518,7 +518,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -552,7 +552,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -565,7 +565,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"testing/service1/carotte": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -599,7 +599,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -612,7 +612,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"toto/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -664,7 +664,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/8080": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -696,7 +696,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/example-com/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -733,7 +733,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/443": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -763,7 +763,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/8443": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -794,7 +794,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/8443": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -825,7 +825,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-backend": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -855,7 +855,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue