From 57ae9a80d5ccba29c8f566a8be4c27512727d9ac Mon Sep 17 00:00:00 2001 From: Andy Kipp Date: Wed, 27 Mar 2019 13:48:04 -0300 Subject: [PATCH] Support external name service on global default backend --- provider/kubernetes/kubernetes.go | 77 +++++++++++++++++--------- provider/kubernetes/kubernetes_test.go | 53 ++++++++++++++++++ 2 files changed, 103 insertions(+), 27 deletions(-) diff --git a/provider/kubernetes/kubernetes.go b/provider/kubernetes/kubernetes.go index 610f6bc70..46cd673ac 100644 --- a/provider/kubernetes/kubernetes.go +++ b/provider/kubernetes/kubernetes.go @@ -503,39 +503,62 @@ func (p *Provider) addGlobalBackend(cl Client, i *extensionsv1beta1.Ingress, tem templateObjects.Backends[defaultBackendName].ResponseForwarding = getResponseForwarding(service) for _, port := range service.Spec.Ports { - endpoints, exists, err := cl.GetEndpoints(service.Namespace, service.Name) - if err != nil { - return fmt.Errorf("error retrieving endpoint information from k8s API %s/%s: %v", service.Namespace, service.Name, err) - } - if !exists { - return fmt.Errorf("endpoints not found for %s/%s", service.Namespace, service.Name) - } - if len(endpoints.Subsets) == 0 { - return fmt.Errorf("endpoints not available for %s/%s", service.Namespace, service.Name) - } - for _, subset := range endpoints.Subsets { - endpointPort := endpointPortNumber(port, subset.Ports) - if endpointPort == 0 { - // endpoint port does not match service. - continue - } + // We have to treat external-name service differently here b/c it doesn't have any endpoints + if service.Spec.Type == corev1.ServiceTypeExternalName { protocol := "http" - for _, address := range subset.Addresses { - if endpointPort == 443 || strings.HasPrefix(i.Spec.Backend.ServicePort.String(), "https") { - protocol = "https" + if port.Port == 443 || strings.HasPrefix(port.Name, "https") { + protocol = "https" + } + + url := protocol + "://" + service.Spec.ExternalName + if port.Port != 443 && port.Port != 80 { + url = fmt.Sprintf("%s:%d", url, port.Port) + } + + templateObjects.Backends[defaultBackendName].Servers[url] = types.Server{ + URL: url, + Weight: label.DefaultWeight, + } + + } else { + + endpoints, exists, err := cl.GetEndpoints(service.Namespace, service.Name) + if err != nil { + return fmt.Errorf("error retrieving endpoint information from k8s API %s/%s: %v", service.Namespace, service.Name, err) + } + if !exists { + return fmt.Errorf("endpoints not found for %s/%s", service.Namespace, service.Name) + } + if len(endpoints.Subsets) == 0 { + return fmt.Errorf("endpoints not available for %s/%s", service.Namespace, service.Name) + } + + for _, subset := range endpoints.Subsets { + + endpointPort := endpointPortNumber(port, subset.Ports) + if endpointPort == 0 { + // endpoint port does not match service. + continue } - url := fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(address.IP, strconv.FormatInt(int64(endpointPort), 10))) - name := url - if address.TargetRef != nil && address.TargetRef.Name != "" { - name = address.TargetRef.Name - } + protocol := "http" + for _, address := range subset.Addresses { + if endpointPort == 443 || strings.HasPrefix(i.Spec.Backend.ServicePort.String(), "https") { + protocol = "https" + } - templateObjects.Backends[defaultBackendName].Servers[name] = types.Server{ - URL: url, - Weight: label.DefaultWeight, + url := fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(address.IP, strconv.FormatInt(int64(endpointPort), 10))) + name := url + if address.TargetRef != nil && address.TargetRef.Name != "" { + name = address.TargetRef.Name + } + + templateObjects.Backends[defaultBackendName].Servers[name] = types.Server{ + URL: url, + Weight: label.DefaultWeight, + } } } } diff --git a/provider/kubernetes/kubernetes_test.go b/provider/kubernetes/kubernetes_test.go index fe301d24e..dae718278 100644 --- a/provider/kubernetes/kubernetes_test.go +++ b/provider/kubernetes/kubernetes_test.go @@ -284,6 +284,59 @@ func TestLoadIngresses(t *testing.T) { assert.Equal(t, expected, actual) } +func TestLoadGlobalIngressWithExternalName(t *testing.T) { + ingresses := []*extensionsv1beta1.Ingress{ + buildIngress( + iNamespace("testing"), + iSpecBackends(iSpecBackend(iIngressBackend("service1", intstr.FromInt(80)))), + ), + } + + services := []*corev1.Service{ + buildService( + sName("service1"), + sNamespace("testing"), + sUID("1"), + sSpec( + sType("ExternalName"), + sExternalName("some-external-name"), + sPorts(sPort(80, ""))), + ), + } + + watchChan := make(chan interface{}) + client := clientMock{ + ingresses: ingresses, + services: services, + watchChan: watchChan, + } + provider := Provider{} + + actual, err := provider.loadIngresses(client) + require.NoError(t, err, "error loading ingresses") + + expected := buildConfiguration( + backends( + backend("global-default-backend", + lbMethod("wrr"), + servers( + server("http://some-external-name", weight(1)), + ), + ), + ), + frontends( + frontend("global-default-backend", + frontendName("global-default-frontend"), + passHostHeader(), + routes( + route("/", "PathPrefix:/"), + ), + ), + ), + ) + assert.Equal(t, expected, actual) +} + func TestLoadGlobalIngressWithPortNumbers(t *testing.T) { ingresses := []*extensionsv1beta1.Ingress{ buildIngress(