Support canary weight for external name service

This commit is contained in:
Kim Min 2018-11-06 14:48:03 +08:00 committed by Traefiker Bot
parent fa562dc916
commit 057498ed01
4 changed files with 61 additions and 7 deletions

View file

@ -357,15 +357,16 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
continue continue
} }
if service.Spec.Type == "ExternalName" { // We have to treat external-name service differently here b/c it doesn't have any endpoints
if service.Spec.Type == corev1.ServiceTypeExternalName {
url := protocol + "://" + service.Spec.ExternalName url := protocol + "://" + service.Spec.ExternalName
if port.Port != 443 && port.Port != 80 { if port.Port != 443 && port.Port != 80 {
url = fmt.Sprintf("%s:%d", url, port.Port) url = fmt.Sprintf("%s:%d", url, port.Port)
} }
externalNameServiceWeight := weightAllocator.getWeight(r.Host, pa.Path, pa.Backend.ServiceName)
templateObjects.Backends[baseName].Servers[url] = types.Server{ templateObjects.Backends[baseName].Servers[url] = types.Server{
URL: url, URL: url,
Weight: label.DefaultWeight, Weight: externalNameServiceWeight,
} }
} else { } else {
endpoints, exists, err := k8sClient.GetEndpoints(service.Namespace, service.Name) endpoints, exists, err := k8sClient.GetEndpoints(service.Namespace, service.Name)

View file

@ -3232,6 +3232,7 @@ func TestPercentageWeightServiceAnnotation(t *testing.T) {
buildIngress( buildIngress(
iAnnotation(annotationKubernetesServiceWeights, ` iAnnotation(annotationKubernetesServiceWeights, `
service1: 10% service1: 10%
service3: 20%
`), `),
iNamespace("testing"), iNamespace("testing"),
iRules( iRules(
@ -3240,6 +3241,7 @@ service1: 10%
iPaths( iPaths(
onePath(iPath("/foo"), iBackend("service1", intstr.FromString("8080"))), onePath(iPath("/foo"), iBackend("service1", intstr.FromString("8080"))),
onePath(iPath("/foo"), iBackend("service2", intstr.FromString("7070"))), onePath(iPath("/foo"), iBackend("service2", intstr.FromString("7070"))),
onePath(iPath("/foo"), iBackend("service3", intstr.FromString("9090"))),
onePath(iPath("/bar"), iBackend("service2", intstr.FromString("7070"))), onePath(iPath("/bar"), iBackend("service2", intstr.FromString("7070"))),
)), )),
), ),
@ -3264,6 +3266,16 @@ service1: 10%
sPorts(sPort(7070, "")), sPorts(sPort(7070, "")),
), ),
), ),
buildService(
sName("service3"),
sNamespace("testing"),
sUID("1"),
sSpec(
sType(corev1.ServiceTypeExternalName),
sExternalName("example.com"),
sPorts(sPort(9090, "")),
),
),
} }
endpoints := []*corev1.Endpoints{ endpoints := []*corev1.Endpoints{
@ -3311,8 +3323,9 @@ service1: 10%
servers( servers(
server("http://10.10.0.1:8080", weight(int(newPercentageValueFromFloat64(0.05)))), server("http://10.10.0.1:8080", weight(int(newPercentageValueFromFloat64(0.05)))),
server("http://10.10.0.2:8080", weight(int(newPercentageValueFromFloat64(0.05)))), server("http://10.10.0.2:8080", weight(int(newPercentageValueFromFloat64(0.05)))),
server("http://10.10.0.3:7070", weight(int(newPercentageValueFromFloat64(0.45)))), server("http://10.10.0.3:7070", weight(int(newPercentageValueFromFloat64(0.35)))),
server("http://10.10.0.4:7070", weight(int(newPercentageValueFromFloat64(0.45)))), server("http://10.10.0.4:7070", weight(int(newPercentageValueFromFloat64(0.35)))),
server("http://example.com:9090", weight(int(newPercentageValueFromFloat64(0.2)))),
), ),
lbMethod("wrr"), lbMethod("wrr"),
), ),

View file

@ -7,6 +7,7 @@ import (
"github.com/containous/traefik/old/provider/label" "github.com/containous/traefik/old/provider/label"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
) )
@ -165,6 +166,23 @@ func getServiceInstanceCounts(ingress *extensionsv1beta1.Ingress, client Client)
for _, rule := range ingress.Spec.Rules { for _, rule := range ingress.Spec.Rules {
for _, pa := range rule.HTTP.Paths { for _, pa := range rule.HTTP.Paths {
svc, exists, err := client.GetService(ingress.Namespace, pa.Backend.ServiceName)
if err != nil {
return nil, fmt.Errorf("failed to get service %s/%s: %v", ingress.Namespace, pa.Backend.ServiceName, err)
}
if !exists {
return nil, fmt.Errorf("service not found for %s/%s", ingress.Namespace, pa.Backend.ServiceName)
}
if svc.Spec.Type == corev1.ServiceTypeExternalName {
// external-name service has only one instance b/c it will actually be interpreted as a DNS record
// instead of real server.
serviceInstanceCounts[ingressService{
host: rule.Host,
path: pa.Path,
service: pa.Backend.ServiceName,
}] = 1
continue
}
count := 0 count := 0
endpoints, exists, err := client.GetEndpoints(ingress.Namespace, pa.Backend.ServiceName) endpoints, exists, err := client.GetEndpoints(ingress.Namespace, pa.Backend.ServiceName)
if err != nil { if err != nil {

View file

@ -169,6 +169,24 @@ service1: 1000%
func TestComputeServiceWeights(t *testing.T) { func TestComputeServiceWeights(t *testing.T) {
client := clientMock{ client := clientMock{
services: []*corev1.Service{
buildService(
sName("service1"),
sNamespace("testing"),
),
buildService(
sName("service2"),
sNamespace("testing"),
),
buildService(
sName("service3"),
sNamespace("testing"),
),
buildService(
sName("service4"),
sNamespace("testing"),
),
},
endpoints: []*corev1.Endpoints{ endpoints: []*corev1.Endpoints{
buildEndpoint( buildEndpoint(
eNamespace("testing"), eNamespace("testing"),
@ -446,8 +464,12 @@ service2: 80%
if test.expectError { if test.expectError {
require.Error(t, err) require.Error(t, err)
} else { } else {
for ingSvc, percentage := range test.expectedWeights { if err != nil {
assert.Equal(t, int(percentage), weightAllocator.getWeight(ingSvc.host, ingSvc.path, ingSvc.service)) t.Errorf("%v failed: %v", test.desc, err)
} else {
for ingSvc, percentage := range test.expectedWeights {
assert.Equal(t, int(percentage), weightAllocator.getWeight(ingSvc.host, ingSvc.path, ingSvc.service))
}
} }
} }
}) })