Upgrade IngressClass to use v1 over v1Beta on Kube 1.19+

This commit is contained in:
Manuel Zapf 2021-05-17 16:50:09 +02:00 committed by GitHub
parent 63ef0f1cee
commit e1e1fd640c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 12 deletions

View file

@ -41,7 +41,7 @@ type marshaler interface {
type Client interface {
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
GetIngresses() []*networkingv1.Ingress
GetIngressClasses() ([]*networkingv1beta1.IngressClass, error)
GetIngressClasses() ([]*networkingv1.IngressClass, error)
GetService(namespace, name string) (*corev1.Service, bool, error)
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
@ -207,7 +207,13 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
if supportsIngressClass(serverVersion) {
c.clusterFactory = informers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod)
if supportsNetworkingV1Ingress(serverVersion) {
c.clusterFactory.Networking().V1().IngressClasses().Informer().AddEventHandler(eventHandler)
} else {
c.clusterFactory.Networking().V1beta1().IngressClasses().Informer().AddEventHandler(eventHandler)
}
c.clusterFactory.Start(stopCh)
for typ, ok := range c.clusterFactory.WaitForCacheSync(stopCh) {
@ -282,6 +288,21 @@ func toNetworkingV1(ing marshaler) (*networkingv1.Ingress, error) {
return ni, nil
}
func toNetworkingV1IngressClass(ing marshaler) (*networkingv1.IngressClass, error) {
data, err := ing.Marshal()
if err != nil {
return nil, err
}
ni := &networkingv1.IngressClass{}
err = ni.Unmarshal(data)
if err != nil {
return nil, err
}
return ni, nil
}
func addServiceFromV1Beta1(ing *networkingv1.Ingress, old networkingv1beta1.Ingress) {
if old.Spec.Backend != nil {
port := networkingv1.ServiceBackendPort{}
@ -450,17 +471,43 @@ func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool,
return secret, exist, err
}
func (c *clientWrapper) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error) {
func (c *clientWrapper) GetIngressClasses() ([]*networkingv1.IngressClass, error) {
serverVersion, err := c.GetServerVersion()
if err != nil {
log.WithoutContext().Errorf("Failed to get server version: %v", err)
return nil, err
}
if c.clusterFactory == nil {
return nil, errors.New("cluster factory not loaded")
}
var ics []*networkingv1.IngressClass
if !supportsNetworkingV1Ingress(serverVersion) {
ingressClasses, err := c.clusterFactory.Networking().V1beta1().IngressClasses().Lister().List(labels.Everything())
if err != nil {
return nil, err
}
var ics []*networkingv1beta1.IngressClass
for _, ic := range ingressClasses {
if ic.Spec.Controller == traefikDefaultIngressClassController {
icN, err := toNetworkingV1IngressClass(ic)
if err != nil {
log.WithoutContext().Errorf("Failed to convert ingress class %s from networking/v1beta1 to networking/v1: %v", ic.Name, err)
continue
}
ics = append(ics, icN)
}
}
return ics, nil
}
ingressClasses, err := c.clusterFactory.Networking().V1().IngressClasses().Lister().List(labels.Everything())
if err != nil {
return nil, err
}
for _, ic := range ingressClasses {
if ic.Spec.Controller == traefikDefaultIngressClassController {
ics = append(ics, ic)
@ -525,8 +572,8 @@ func supportsIngressClass(serverVersion *version.Version) bool {
}
// filterIngressClassByName return a slice containing ingressclasses with the correct name.
func filterIngressClassByName(ingressClassName string, ics []*networkingv1beta1.IngressClass) []*networkingv1beta1.IngressClass {
var ingressClasses []*networkingv1beta1.IngressClass
func filterIngressClassByName(ingressClassName string, ics []*networkingv1.IngressClass) []*networkingv1.IngressClass {
var ingressClasses []*networkingv1.IngressClass
for _, ic := range ics {
if ic.Name == ingressClassName {

View file

@ -18,7 +18,7 @@ type clientMock struct {
services []*corev1.Service
secrets []*corev1.Secret
endpoints []*corev1.Endpoints
ingressClasses []*networkingv1beta1.IngressClass
ingressClasses []*networkingv1.IngressClass
serverVersion *version.Version
@ -60,6 +60,12 @@ func newClientMock(serverVersion string, paths ...string) clientMock {
case *networkingv1.Ingress:
c.ingresses = append(c.ingresses, o)
case *networkingv1beta1.IngressClass:
ic, err := toNetworkingV1IngressClass(o)
if err != nil {
panic(err)
}
c.ingressClasses = append(c.ingressClasses, ic)
case *networkingv1.IngressClass:
c.ingressClasses = append(c.ingressClasses, o)
default:
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
@ -118,7 +124,7 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
return nil, false, nil
}
func (c clientMock) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error) {
func (c clientMock) GetIngressClasses() ([]*networkingv1.IngressClass, error) {
return c.ingressClasses, nil
}

View file

@ -0,0 +1,11 @@
kind: Endpoints
apiVersion: v1
metadata:
name: service1
namespace: testing
subsets:
- addresses:
- ip: 10.10.0.1
ports:
- port: 8080

View file

@ -0,0 +1,16 @@
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: ""
namespace: testing
spec:
ingressClassName: traefik-lb-v1
rules:
- http:
paths:
- path: /bar
backend:
service:
name: service1
port:
number: 80

View file

@ -0,0 +1,6 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb-v1
spec:
controller: traefik.io/ingress-controller

View file

@ -0,0 +1,10 @@
kind: Service
apiVersion: v1
metadata:
name: service1
namespace: testing
spec:
ports:
- port: 80
clusterIP: 10.0.0.1

View file

@ -24,7 +24,6 @@ import (
"github.com/traefik/traefik/v2/pkg/tls"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
"k8s.io/apimachinery/pkg/labels"
)
@ -191,7 +190,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
return conf
}
var ingressClasses []*networkingv1beta1.IngressClass
var ingressClasses []*networkingv1.IngressClass
if supportsIngressClass(serverVersion) {
ics, err := client.GetIngressClasses()
@ -378,7 +377,7 @@ func (p *Provider) updateIngressStatus(ing *networkingv1.Ingress, k8sClient Clie
return k8sClient.UpdateIngressStatus(ing, service.Status.LoadBalancer.Ingress)
}
func (p *Provider) shouldProcessIngress(ingress *networkingv1.Ingress, ingressClasses []*networkingv1beta1.IngressClass) bool {
func (p *Provider) shouldProcessIngress(ingress *networkingv1.Ingress, ingressClasses []*networkingv1.IngressClass) bool {
// configuration through the new kubernetes ingressClass
if ingress.Spec.IngressClassName != nil {
for _, ic := range ingressClasses {

View file

@ -1538,6 +1538,34 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
},
},
{
desc: "v19 Ingress with ingressClassv1",
serverVersion: "v1.19",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-bar": {
Rule: "PathPrefix(`/bar`)",
Service: "testing-service1-80",
},
},
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
},
},
},
},
},
},
},
},
{
desc: "v19 Ingress with named port",
serverVersion: "v1.19",