Support canary weight for external name service
This commit is contained in:
parent
fa562dc916
commit
057498ed01
4 changed files with 61 additions and 7 deletions
|
@ -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)
|
||||||
|
|
|
@ -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"),
|
||||||
),
|
),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue