From 799136a714216a1bf9189b6d4862117b8bd02998 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 15 Dec 2017 01:22:03 +0100 Subject: [PATCH] fix: backend name for Stateful services. (Service Fabric) --- glide.lock | 8 +- glide.yaml | 2 +- .../traefik-extra-service-fabric/labels.go | 62 ++++-- .../servicefabric.go | 188 ++++++++---------- .../servicefabric_tmpl.go | 64 +++--- .../jjcollinge/servicefabric/servicefabric.go | 1 + 6 files changed, 174 insertions(+), 151 deletions(-) diff --git a/glide.lock b/glide.lock index d3d61ab95..f35752694 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 798765d68f54df534f091b4963f76f3e26d8dac2cb444368c2fa1c572e3c1ea6 -updated: 2017-11-30T10:34:41.246378337+01:00 +hash: 03cd7f5ecab087e73cc395cb61b58b82cefef55969aa368f93fc17095b92815f +updated: 2017-12-15T10:34:41.246378337+01:00 imports: - name: cloud.google.com/go version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c @@ -94,7 +94,7 @@ imports: - name: github.com/containous/staert version: af517d5b70db9c4b0505e0144fcc62b054057d2a - name: github.com/containous/traefik-extra-service-fabric - version: 8076098dbfe814cba9e895ecbd896f1896b6b2d5 + version: c01c1ef60ed612c5e42c1ceae0c6f92e67619cc3 - name: github.com/coreos/bbolt version: 3c6cbfb299c11444eb2f8c9d48f0d2ce09157423 - name: github.com/coreos/etcd @@ -348,7 +348,7 @@ imports: subpackages: - lib - name: github.com/jjcollinge/servicefabric - version: 93a44e59fc887cda489913c6fc5bda834989f3bd + version: 8026935326c842b71dee8e2329c1fda41a7a92f4 - name: github.com/jmespath/go-jmespath version: bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d - name: github.com/jonboulle/clockwork diff --git a/glide.yaml b/glide.yaml index 5e387f1aa..f582a9187 100644 --- a/glide.yaml +++ b/glide.yaml @@ -12,7 +12,7 @@ import: - package: github.com/cenk/backoff - package: github.com/containous/flaeg - package: github.com/containous/traefik-extra-service-fabric - version: v1.0.1 + version: v1.0.4 - package: github.com/vulcand/oxy version: 7b6e758ab449705195df638765c4ca472248908a repo: https://github.com/containous/oxy.git diff --git a/vendor/github.com/containous/traefik-extra-service-fabric/labels.go b/vendor/github.com/containous/traefik-extra-service-fabric/labels.go index 2dea665ae..f2878d20a 100644 --- a/vendor/github.com/containous/traefik-extra-service-fabric/labels.go +++ b/vendor/github.com/containous/traefik-extra-service-fabric/labels.go @@ -1,23 +1,59 @@ package servicefabric -import "strings" +import ( + "strconv" + "strings" +) -func hasServiceLabel(service ServiceItemExtended, key string) bool { - _, exists := service.Labels[key] - return exists -} - -func getFuncBoolLabel(labelName string) func(service ServiceItemExtended) bool { +func getFuncBoolLabel(labelName string, defaultValue bool) func(service ServiceItemExtended) bool { return func(service ServiceItemExtended) bool { - return getBoolLabel(service, labelName) + return getBoolValue(service.Labels, labelName, defaultValue) } } -func getBoolLabel(service ServiceItemExtended, labelName string) bool { - value, exists := service.Labels[labelName] - return exists && strings.EqualFold(strings.TrimSpace(value), "true") +func getFuncServiceStringLabel(service ServiceItemExtended, labelName string, defaultValue string) string { + return getStringValue(service.Labels, labelName, defaultValue) } -func getServiceLabelValue(service ServiceItemExtended, key string) string { - return service.Labels[key] +func hasFuncService(service ServiceItemExtended, labelName string) bool { + return hasLabel(service.Labels, labelName) +} + +func getServiceLabelsWithPrefix(service ServiceItemExtended, prefix string) map[string]string { + results := make(map[string]string) + for k, v := range service.Labels { + if strings.HasPrefix(k, prefix) { + results[k] = v + } + } + return results +} + +// must be replace by label.Has() +// Deprecated +func hasLabel(labels map[string]string, labelName string) bool { + value, ok := labels[labelName] + return ok && len(value) > 0 +} + +// must be replace by label.GetStringValue() +// Deprecated +func getStringValue(labels map[string]string, labelName string, defaultValue string) string { + if value, ok := labels[labelName]; ok && len(value) > 0 { + return value + } + return defaultValue +} + +// must be replace by label.GetBoolValue() +// Deprecated +func getBoolValue(labels map[string]string, labelName string, defaultValue bool) bool { + rawValue, ok := labels[labelName] + if ok { + v, err := strconv.ParseBool(rawValue) + if err == nil { + return v + } + } + return defaultValue } diff --git a/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go b/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go index 79ed5ef57..8183d9480 100644 --- a/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go +++ b/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go @@ -69,34 +69,7 @@ func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, po log.Info("Checking service fabric config") } - services, err := getClusterServices(sfClient) - if err != nil { - return err - } - - templateObjects := struct { - Services []ServiceItemExtended - }{ - services, - } - - var sfFuncMap = template.FuncMap{ - "isPrimary": isPrimary, - "getDefaultEndpoint": p.getDefaultEndpoint, - "getNamedEndpoint": p.getNamedEndpoint, - "getApplicationParameter": p.getApplicationParameter, - "doesAppParamContain": p.doesAppParamContain, - "hasServiceLabel": hasServiceLabel, - "getServiceLabelValue": getServiceLabelValue, - "getServiceLabelValueWithDefault": getServiceLabelValueWithDefault, - "getServiceLabelsWithPrefix": getServiceLabelsWithPrefix, - "getServicesWithLabelValueMap": getServicesWithLabelValueMap, - "getServicesWithLabelValue": getServicesWithLabelValue, - "isExposed": getFuncBoolLabel("expose"), - } - - configuration, err := p.GetConfiguration(tmpl, sfFuncMap, templateObjects) - + configuration, err := p.buildConfiguration(sfClient) if err != nil { return err } @@ -120,24 +93,39 @@ func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, po return nil } -func (p Provider) doesAppParamContain(app sf.ApplicationItem, key, shouldContain string) bool { - value := p.getApplicationParameter(app, key) - return strings.Contains(value, shouldContain) -} - -func (p Provider) getApplicationParameter(app sf.ApplicationItem, key string) string { - for _, param := range app.Parameters { - if param.Key == key { - return param.Value - } +func (p *Provider) buildConfiguration(sfClient sfClient) (*types.Configuration, error) { + var sfFuncMap = template.FuncMap{ + "getServices": getServices, + "hasLabel": hasFuncService, + "getLabelValue": getFuncServiceStringLabel, + "getLabelsWithPrefix": getServiceLabelsWithPrefix, + "isPrimary": isPrimary, + "isExposed": getFuncBoolLabel("expose", false), + "getBackendName": getBackendName, + "getDefaultEndpoint": getDefaultEndpoint, + "getNamedEndpoint": getNamedEndpoint, // FIXME unused + "getApplicationParameter": getApplicationParameter, // FIXME unused + "doesAppParamContain": doesAppParamContain, // FIXME unused + "filterServicesByLabelValue": filterServicesByLabelValue, // FIXME unused } - log.Errorf("Parameter %s doesn't exist in app %s", key, app.Name) - return "" + + services, err := getClusterServices(sfClient) + if err != nil { + return nil, err + } + + templateObjects := struct { + Services []ServiceItemExtended + }{ + Services: services, + } + + return p.GetConfiguration(tmpl, sfFuncMap, templateObjects) } -func (p Provider) getDefaultEndpoint(instance replicaInstance) string { +func getDefaultEndpoint(instance replicaInstance) string { id, data := instance.GetReplicaData() - endpoint, err := getDefaultEndpoint(data.Address) + endpoint, err := getReplicaDefaultEndpoint(data) if err != nil { log.Warnf("No default endpoint for replica %s in service %s endpointData: %s", id, data.Address) return "" @@ -145,16 +133,64 @@ func (p Provider) getDefaultEndpoint(instance replicaInstance) string { return endpoint } -func (p Provider) getNamedEndpoint(instance replicaInstance, endpointName string) string { - id, data := instance.GetReplicaData() - endpoint, err := getNamedEndpoint(data.Address, endpointName) +func getReplicaDefaultEndpoint(replicaData *sf.ReplicaItemBase) (string, error) { + endpoints, err := decodeEndpointData(replicaData.Address) if err != nil { - log.Warnf("No names endpoint of %s for replica %s in endpointData: %s", endpointName, id, data.Address) + return "", err + } + + var defaultHTTPEndpoint string + for _, v := range endpoints { + if strings.Contains(v, "http") { + defaultHTTPEndpoint = v + break + } + } + + if len(defaultHTTPEndpoint) == 0 { + return "", errors.New("no default endpoint found") + } + return defaultHTTPEndpoint, nil +} + +func getNamedEndpoint(instance replicaInstance, endpointName string) string { + id, data := instance.GetReplicaData() + endpoint, err := getReplicaNamedEndpoint(data, endpointName) + if err != nil { + log.Warnf("No names endpoint of %s for replica %s in endpointData: %s. Error: %v", endpointName, id, data.Address, err) return "" } return endpoint } +func getReplicaNamedEndpoint(replicaData *sf.ReplicaItemBase, endpointName string) (string, error) { + endpoints, err := decodeEndpointData(replicaData.Address) + if err != nil { + return "", err + } + + endpoint, exists := endpoints[endpointName] + if !exists { + return "", errors.New("endpoint doesn't exist") + } + return endpoint, nil +} + +func doesAppParamContain(app sf.ApplicationItem, key, shouldContain string) bool { + value := getApplicationParameter(app, key) + return strings.Contains(value, shouldContain) +} + +func getApplicationParameter(app sf.ApplicationItem, key string) string { + for _, param := range app.Parameters { + if param.Key == key { + return param.Value + } + } + log.Errorf("Parameter %s doesn't exist in app %s", key, app.Name) + return "" +} + func getClusterServices(sfClient sfClient) ([]ServiceItemExtended, error) { apps, err := sfClient.GetApplications() if err != nil { @@ -236,7 +272,7 @@ func getValidInstances(sfClient sfClient, app sf.ApplicationItem, service sf.Ser return validInstances } -func getServicesWithLabelValueMap(services []ServiceItemExtended, key string) map[string][]ServiceItemExtended { +func getServices(services []ServiceItemExtended, key string) map[string][]ServiceItemExtended { result := map[string][]ServiceItemExtended{} for _, service := range services { if value, exists := service.Labels[key]; exists { @@ -250,7 +286,7 @@ func getServicesWithLabelValueMap(services []ServiceItemExtended, key string) ma return result } -func getServicesWithLabelValue(services []ServiceItemExtended, key, expectedValue string) []ServiceItemExtended { +func filterServicesByLabelValue(services []ServiceItemExtended, key, expectedValue string) []ServiceItemExtended { var srvWithLabel []ServiceItemExtended for _, service := range services { value, exists := service.Labels[key] @@ -261,25 +297,6 @@ func getServicesWithLabelValue(services []ServiceItemExtended, key, expectedValu return srvWithLabel } -func getServiceLabelValueWithDefault(service ServiceItemExtended, key, defaultValue string) string { - value, exists := service.Labels[key] - - if !exists { - return defaultValue - } - return value -} - -func getServiceLabelsWithPrefix(service ServiceItemExtended, prefix string) map[string]string { - results := make(map[string]string) - for k, v := range service.Labels { - if strings.HasPrefix(k, prefix) { - results[k] = v - } - } - return results -} - func isPrimary(instance replicaInstance) bool { _, data := instance.GetReplicaData() return data.ReplicaRole == "Primary" @@ -290,7 +307,7 @@ func isHealthy(instanceData *sf.ReplicaItemBase) bool { } func hasHTTPEndpoint(instanceData *sf.ReplicaItemBase) bool { - _, err := getDefaultEndpoint(instanceData.Address) + _, err := getReplicaDefaultEndpoint(instanceData) return err == nil } @@ -314,37 +331,6 @@ func decodeEndpointData(endpointData string) (map[string]string, error) { return endpoints, nil } -func getDefaultEndpoint(endpointData string) (string, error) { - endpoints, err := decodeEndpointData(endpointData) - if err != nil { - return "", err - } - - var defaultHTTPEndpointExists bool - var defaultHTTPEndpoint string - for _, v := range endpoints { - if strings.Contains(v, "http") { - defaultHTTPEndpoint = v - defaultHTTPEndpointExists = true - break - } - } - - if !defaultHTTPEndpointExists { - return "", errors.New("no default endpoint found") - } - return defaultHTTPEndpoint, nil -} - -func getNamedEndpoint(endpointData string, endpointName string) (string, error) { - endpoints, err := decodeEndpointData(endpointData) - if err != nil { - return "", err - } - - endpoint, exists := endpoints[endpointName] - if !exists { - return "", errors.New("endpoint doesn't exist") - } - return endpoint, nil +func getBackendName(service ServiceItemExtended, partition PartitionItemExtended) string { + return provider.Normalize(service.Name + partition.PartitionInformation.ID) } diff --git a/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_tmpl.go b/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_tmpl.go index d7af11912..74be5033d 100644 --- a/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_tmpl.go +++ b/vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_tmpl.go @@ -1,8 +1,8 @@ package servicefabric const tmpl = ` +{{$groupedServiceMap := getServices .Services "backend.group.name"}} [backends] - {{$groupedServiceMap := getServicesWithLabelValueMap .Services "backend.group.name"}} {{range $aggName, $aggServices := $groupedServiceMap }} [backends."{{$aggName}}"] {{range $service := $aggServices}} @@ -10,7 +10,7 @@ const tmpl = ` {{range $instance := $partition.Instances}} [backends."{{$aggName}}".servers."{{$service.ID}}-{{$instance.ID}}"] url = "{{getDefaultEndpoint $instance}}" - weight = {{getServiceLabelValueWithDefault $service "backend.group.weight" "1"}} + weight = {{getLabelValue $service "backend.group.weight" "1"}} {{end}} {{end}} {{end}} @@ -20,45 +20,45 @@ const tmpl = ` {{if eq $partition.ServiceKind "Stateless"}} [backends."{{$service.Name}}"] [backends."{{$service.Name}}".LoadBalancer] - {{if hasServiceLabel $service "backend.loadbalancer.method"}} - method = "{{getServiceLabelValue $service "backend.loadbalancer.method" }}" + {{if hasLabel $service "backend.loadbalancer.method"}} + method = "{{getLabelValue $service "backend.loadbalancer.method" "" }}" {{else}} method = "drr" {{end}} - {{if hasServiceLabel $service "backend.healthcheck"}} + {{if hasLabel $service "backend.healthcheck"}} [backends."{{$service.Name}}".healthcheck] - path = "{{getServiceLabelValue $service "backend.healthcheck"}}" - interval = "{{getServiceLabelValueWithDefault $service "backend.healthcheck.interval" "10s"}}" + path = "{{getLabelValue $service "backend.healthcheck" ""}}" + interval = "{{getLabelValue $service "backend.healthcheck.interval" "10s"}}" {{end}} - {{if hasServiceLabel $service "backend.loadbalancer.stickiness"}} + {{if hasLabel $service "backend.loadbalancer.stickiness"}} [backends."{{$service.Name}}".LoadBalancer.stickiness] {{end}} - {{if hasServiceLabel $service "backend.circuitbreaker"}} + {{if hasLabel $service "backend.circuitbreaker"}} [backends."{{$service.Name}}".circuitbreaker] - expression = "{{getServiceLabelValue $service "backend.circuitbreaker"}}" + expression = "{{getLabelValue $service "backend.circuitbreaker" ""}}" {{end}} - {{if hasServiceLabel $service "backend.maxconn.amount"}} + {{if hasLabel $service "backend.maxconn.amount"}} [backends."{{$service.Name}}".maxconn] - amount = {{getServiceLabelValue $service "backend.maxconn.amount"}} - {{if hasServiceLabel $service "backend.maxconn.extractorfunc"}} - extractorfunc = "{{getServiceLabelValue $service "backend.maxconn.extractorfunc"}}" + amount = {{getLabelValue $service "backend.maxconn.amount" ""}} + {{if hasLabel $service "backend.maxconn.extractorfunc"}} + extractorfunc = "{{getLabelValue $service "backend.maxconn.extractorfunc" ""}}" {{end}} {{end}} {{range $instance := $partition.Instances}} [backends."{{$service.Name}}".servers."{{$instance.ID}}"] url = "{{getDefaultEndpoint $instance}}" - weight = {{getServiceLabelValueWithDefault $service "backend.weight" "1"}} + weight = {{getLabelValue $service "backend.weight" "1"}} {{end}} {{else if eq $partition.ServiceKind "Stateful"}} {{range $replica := $partition.Replicas}} {{if isPrimary $replica}} - {{$backendName := (print $service.Name $partition.PartitionInformation.ID)}} + {{$backendName := getBackendName $service.Name $partition}} [backends."{{$backendName}}".servers."{{$replica.ID}}"] url = "{{getDefaultEndpoint $replica}}" weight = 1 @@ -81,11 +81,11 @@ const tmpl = ` [frontends."{{$groupName}}"] backend = "{{$groupName}}" - {{if hasServiceLabel $service "frontend.priority"}} + {{if hasLabel $service "frontend.priority"}} priority = 100 {{end}} - {{range $key, $value := getServiceLabelsWithPrefix $service "frontend.rule"}} + {{range $key, $value := getLabelsWithPrefix $service "frontend.rule"}} [frontends."{{$groupName}}".routes."{{$key}}"] rule = "{{$value}}" {{end}} @@ -97,27 +97,27 @@ const tmpl = ` [frontends."{{$service.Name}}"] backend = "{{$service.Name}}" - {{if hasServiceLabel $service "frontend.passHostHeader"}} - passHostHeader = {{getServiceLabelValue $service "frontend.passHostHeader" }} + {{if hasLabel $service "frontend.passHostHeader"}} + passHostHeader = {{getLabelValue $service "frontend.passHostHeader" ""}} {{end}} - {{if hasServiceLabel $service "frontend.whitelistSourceRange"}} - whitelistSourceRange = {{getServiceLabelValue $service "frontend.whitelistSourceRange" }} + {{if hasLabel $service "frontend.whitelistSourceRange"}} + whitelistSourceRange = {{getLabelValue $service "frontend.whitelistSourceRange" ""}} {{end}} - {{if hasServiceLabel $service "frontend.priority"}} - priority = {{getServiceLabelValue $service "frontend.priority"}} + {{if hasLabel $service "frontend.priority"}} + priority = {{getLabelValue $service "frontend.priority" ""}} {{end}} - {{if hasServiceLabel $service "frontend.basicAuth"}} - basicAuth = {{getServiceLabelValue $service "frontend.basicAuth"}} + {{if hasLabel $service "frontend.basicAuth"}} + basicAuth = {{getLabelValue $service "frontend.basicAuth" ""}} {{end}} - {{if hasServiceLabel $service "frontend.entryPoints"}} - entryPoints = {{getServiceLabelValue $service "frontend.entryPoints"}} + {{if hasLabel $service "frontend.entryPoints"}} + entryPoints = {{getLabelValue $service "frontend.entryPoints" ""}} {{end}} - {{range $key, $value := getServiceLabelsWithPrefix $service "frontend.rule"}} + {{range $key, $value := getLabelsWithPrefix $service "frontend.rule"}} [frontends."{{$service.Name}}".routes."{{$key}}"] rule = "{{$value}}" {{end}} @@ -126,11 +126,11 @@ const tmpl = ` {{range $partition := $service.Partitions}} {{$partitionId := $partition.PartitionInformation.ID}} - {{if hasServiceLabel $service "frontend.rule"}} + {{if hasLabel $service "frontend.rule"}} [frontends."{{$service.Name}}/{{$partitionId}}"] - backend = "{{$service.Name}}/{{$partitionId}}" + backend = "{{getBackendName $service.Name $partition}}" [frontends."{{$service.Name}}/{{$partitionId}}".routes.default] - rule = {{getServiceLabelValue $service "frontend.rule.partition.$partitionId"}} + rule = {{getLabelValue $service "frontend.rule.partition.$partitionId" ""}} {{end}} {{end}} diff --git a/vendor/github.com/jjcollinge/servicefabric/servicefabric.go b/vendor/github.com/jjcollinge/servicefabric/servicefabric.go index a46b3ef56..7500ee658 100644 --- a/vendor/github.com/jjcollinge/servicefabric/servicefabric.go +++ b/vendor/github.com/jjcollinge/servicefabric/servicefabric.go @@ -12,6 +12,7 @@ import ( "strings" ) +// DefaultAPIVersion is a default Service Fabric REST API version const DefaultAPIVersion = "3.0" // Client for Service Fabric.