Update Service Fabric backend.
This commit is contained in:
parent
1b410980ca
commit
0fa0c2256a
10 changed files with 677 additions and 352 deletions
9
Gopkg.lock
generated
9
Gopkg.lock
generated
|
@ -247,8 +247,8 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/containous/traefik-extra-service-fabric"
|
name = "github.com/containous/traefik-extra-service-fabric"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "ca1fb57108293caad285b1c366b763f6c6ab71c9"
|
revision = "a0b20089e99069884b060875fc015c13a23e7953"
|
||||||
version = "v1.0.5"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/coreos/bbolt"
|
name = "github.com/coreos/bbolt"
|
||||||
|
@ -745,10 +745,9 @@
|
||||||
version = "v1.3.7"
|
version = "v1.3.7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/jjcollinge/servicefabric"
|
name = "github.com/jjcollinge/servicefabric"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "8026935326c842b71dee8e2329c1fda41a7a92f4"
|
revision = "8eebe170fa1ba25d3dfb928b3f86a7313b13b9fe"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/jmespath/go-jmespath"
|
name = "github.com/jmespath/go-jmespath"
|
||||||
|
@ -1633,6 +1632,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "39b400d9928cce714a46cae410074fd2622a097a9e0faba76a7b21537fabd728"
|
inputs-digest = "ab328aeda9dbd2c4dc87061c25dbfbd151dbdc5946b6f512f676b39bebba8d8e"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/containous/traefik-extra-service-fabric"
|
name = "github.com/containous/traefik-extra-service-fabric"
|
||||||
version = "1.0.5"
|
version = "1.1.0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/coreos/go-systemd"
|
name = "github.com/coreos/go-systemd"
|
||||||
|
|
|
@ -92,23 +92,63 @@ curl -X PUT \
|
||||||
|
|
||||||
## Available Labels
|
## Available Labels
|
||||||
|
|
||||||
Labels, set through extensions or the property manager, can be used on services to override default behaviour.
|
Labels, set through extensions or the property manager, can be used on services to override default behavior.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
| `traefik.enable=false` | Disable this container in Træfik |
|
||||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
|
| `traefik.backend.group.name` | Group all services with the same name into a single backend in Træfik |
|
||||||
|
| `traefik.backend.group.weight` | Set the weighting of the current services nodes in the backend group |
|
||||||
|
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
|
||||||
|
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
|
||||||
|
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. |
|
||||||
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
||||||
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
||||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
|
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
|
||||||
|
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
||||||
|
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||||
| `traefik.backend.weight=10` | Assign this weight to the container |
|
| `traefik.backend.weight=10` | Assign this weight to the container |
|
||||||
| `traefik.expose=true` | Expose this service using træfik |
|
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||||
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Defaults to SF address. |
|
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
|
||||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||||
|
| `traefik.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
|
||||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints` |
|
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||||
| `traefik.frontend.auth.basic=EXPR` | Set basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
||||||
| `traefik.frontend.whitelistSourceRange:RANGE` | List of IP-Ranges which are allowed to access. An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
|
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
||||||
| `traefik.backend.group.name` | Group all services with the same name into a single backend in Træfik |
|
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
|
||||||
| `traefik.backend.group.weight` | Set the weighting of the current services nodes in the backend group |
|
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Defaults to SF address. |
|
||||||
|
| `traefik.frontend.whitelistSourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
|
||||||
|
|
||||||
|
### Custom Headers
|
||||||
|
|
||||||
|
| Label | Description |
|
||||||
|
|-------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `traefik.frontend.headers.customRequestHeaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container.<br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
|
| `traefik.frontend.headers.customResponseHeaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client.<br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
|
|
||||||
|
### Security Headers
|
||||||
|
|
||||||
|
| Label | Description |
|
||||||
|
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
|
||||||
|
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
|
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
|
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
|
||||||
|
| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
|
| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
|
||||||
|
| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
|
||||||
|
| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
|
||||||
|
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
|
||||||
|
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
|
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
|
||||||
|
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
|
||||||
|
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
|
||||||
|
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
|
||||||
|
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
|
||||||
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
||||||
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
|
|
59
vendor/github.com/containous/traefik-extra-service-fabric/labels.go
generated
vendored
59
vendor/github.com/containous/traefik-extra-service-fabric/labels.go
generated
vendored
|
@ -1,59 +0,0 @@
|
||||||
package servicefabric
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getFuncBoolLabel(labelName string, defaultValue bool) func(service ServiceItemExtended) bool {
|
|
||||||
return func(service ServiceItemExtended) bool {
|
|
||||||
return getBoolValue(service.Labels, labelName, defaultValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFuncServiceStringLabel(service ServiceItemExtended, labelName string, defaultValue string) string {
|
|
||||||
return getStringValue(service.Labels, labelName, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
163
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go
generated
vendored
163
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go
generated
vendored
|
@ -1,17 +1,14 @@
|
||||||
package servicefabric
|
package servicefabric
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenk/backoff"
|
"github.com/cenk/backoff"
|
||||||
"github.com/containous/traefik/job"
|
"github.com/containous/traefik/job"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
|
"github.com/containous/traefik/provider/label"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
sf "github.com/jjcollinge/servicefabric"
|
sf "github.com/jjcollinge/servicefabric"
|
||||||
|
@ -19,7 +16,7 @@ import (
|
||||||
|
|
||||||
var _ provider.Provider = (*Provider)(nil)
|
var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
const traefikLabelPrefix = "traefik"
|
const traefikServiceFabricExtensionKey = "Traefik"
|
||||||
|
|
||||||
// Provider holds for configuration for the provider
|
// Provider holds for configuration for the provider
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
|
@ -93,104 +90,6 @@ func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, po
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
services, err := getClusterServices(sfClient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
templateObjects := struct {
|
|
||||||
Services []ServiceItemExtended
|
|
||||||
}{
|
|
||||||
Services: services,
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.GetConfiguration(tmpl, sfFuncMap, templateObjects)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDefaultEndpoint(instance replicaInstance) string {
|
|
||||||
id, data := instance.GetReplicaData()
|
|
||||||
endpoint, err := getReplicaDefaultEndpoint(data)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("No default endpoint for replica %s in service %s endpointData: %s", id, data.Address)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return endpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
func getReplicaDefaultEndpoint(replicaData *sf.ReplicaItemBase) (string, error) {
|
|
||||||
endpoints, err := decodeEndpointData(replicaData.Address)
|
|
||||||
if err != nil {
|
|
||||||
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) {
|
func getClusterServices(sfClient sfClient) ([]ServiceItemExtended, error) {
|
||||||
apps, err := sfClient.GetApplications()
|
apps, err := sfClient.GetApplications()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -210,7 +109,7 @@ func getClusterServices(sfClient sfClient) ([]ServiceItemExtended, error) {
|
||||||
Application: app,
|
Application: app,
|
||||||
}
|
}
|
||||||
|
|
||||||
if labels, err := sfClient.GetServiceLabels(&service, &app, traefikLabelPrefix); err != nil {
|
if labels, err := getLabels(sfClient, &service, &app); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
} else {
|
} else {
|
||||||
item.Labels = labels
|
item.Labels = labels
|
||||||
|
@ -222,9 +121,9 @@ func getClusterServices(sfClient sfClient) ([]ServiceItemExtended, error) {
|
||||||
for _, partition := range partitions.Items {
|
for _, partition := range partitions.Items {
|
||||||
partitionExt := PartitionItemExtended{PartitionItem: partition}
|
partitionExt := PartitionItemExtended{PartitionItem: partition}
|
||||||
|
|
||||||
if partition.ServiceKind == "Stateful" {
|
if isStateful(item) {
|
||||||
partitionExt.Replicas = getValidReplicas(sfClient, app, service, partition)
|
partitionExt.Replicas = getValidReplicas(sfClient, app, service, partition)
|
||||||
} else if partition.ServiceKind == "Stateless" {
|
} else if isStateless(item) {
|
||||||
partitionExt.Instances = getValidInstances(sfClient, app, service, partition)
|
partitionExt.Instances = getValidInstances(sfClient, app, service, partition)
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Unsupported service kind %s in service %s", partition.ServiceKind, service.Name)
|
log.Errorf("Unsupported service kind %s in service %s", partition.ServiceKind, service.Name)
|
||||||
|
@ -272,31 +171,6 @@ func getValidInstances(sfClient sfClient, app sf.ApplicationItem, service sf.Ser
|
||||||
return validInstances
|
return validInstances
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServices(services []ServiceItemExtended, key string) map[string][]ServiceItemExtended {
|
|
||||||
result := map[string][]ServiceItemExtended{}
|
|
||||||
for _, service := range services {
|
|
||||||
if value, exists := service.Labels[key]; exists {
|
|
||||||
if matchingServices, hasKeyAlready := result[value]; hasKeyAlready {
|
|
||||||
result[value] = append(matchingServices, service)
|
|
||||||
} else {
|
|
||||||
result[value] = []ServiceItemExtended{service}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterServicesByLabelValue(services []ServiceItemExtended, key, expectedValue string) []ServiceItemExtended {
|
|
||||||
var srvWithLabel []ServiceItemExtended
|
|
||||||
for _, service := range services {
|
|
||||||
value, exists := service.Labels[key]
|
|
||||||
if exists && value == expectedValue {
|
|
||||||
srvWithLabel = append(srvWithLabel, service)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return srvWithLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPrimary(instance replicaInstance) bool {
|
func isPrimary(instance replicaInstance) bool {
|
||||||
_, data := instance.GetReplicaData()
|
_, data := instance.GetReplicaData()
|
||||||
return data.ReplicaRole == "Primary"
|
return data.ReplicaRole == "Primary"
|
||||||
|
@ -311,26 +185,21 @@ func hasHTTPEndpoint(instanceData *sf.ReplicaItemBase) bool {
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeEndpointData(endpointData string) (map[string]string, error) {
|
// Return a set of labels from the Extension and Property manager
|
||||||
var endpointsMap map[string]map[string]string
|
// Allow Extension labels to disable importing labels from the property manager.
|
||||||
|
func getLabels(sfClient sfClient, service *sf.ServiceItem, app *sf.ApplicationItem) (map[string]string, error) {
|
||||||
if endpointData == "" {
|
labels, err := sfClient.GetServiceExtensionMap(service, app, traefikServiceFabricExtensionKey)
|
||||||
return nil, errors.New("endpoint data is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := json.Unmarshal([]byte(endpointData), &endpointsMap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Errorf("Error retrieving serviceExtensionMap: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints, endpointsExist := endpointsMap["Endpoints"]
|
if label.GetBoolValue(labels, traefikSFEnableLabelOverrides, traefikSFEnableLabelOverridesDefault) {
|
||||||
if !endpointsExist {
|
if exists, properties, err := sfClient.GetProperties(service.ID); err == nil && exists {
|
||||||
return nil, errors.New("endpoint doesn't exist in endpoint data")
|
for key, value := range properties {
|
||||||
|
labels[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
return endpoints, nil
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func getBackendName(service ServiceItemExtended, partition PartitionItemExtended) string {
|
return labels, nil
|
||||||
return provider.Normalize(service.Name + partition.PartitionInformation.ID)
|
|
||||||
}
|
}
|
||||||
|
|
321
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_config.go
generated
vendored
Normal file
321
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_config.go
generated
vendored
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
package servicefabric
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/log"
|
||||||
|
"github.com/containous/traefik/provider"
|
||||||
|
"github.com/containous/traefik/provider/label"
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
|
sf "github.com/jjcollinge/servicefabric"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) buildConfiguration(sfClient sfClient) (*types.Configuration, error) {
|
||||||
|
var sfFuncMap = template.FuncMap{
|
||||||
|
|
||||||
|
// Services
|
||||||
|
"getServices": getServices,
|
||||||
|
"hasLabel": hasService,
|
||||||
|
"getLabelValue": getServiceStringLabel,
|
||||||
|
"getLabelsWithPrefix": getServiceLabelsWithPrefix,
|
||||||
|
"isPrimary": isPrimary,
|
||||||
|
"isStateful": isStateful,
|
||||||
|
"isStateless": isStateless,
|
||||||
|
"isEnabled": getFuncBoolLabel(label.TraefikEnable, false),
|
||||||
|
"getBackendName": getBackendName,
|
||||||
|
"getDefaultEndpoint": getDefaultEndpoint,
|
||||||
|
"getNamedEndpoint": getNamedEndpoint, // FIXME unused
|
||||||
|
"getApplicationParameter": getApplicationParameter, // FIXME unused
|
||||||
|
"doesAppParamContain": doesAppParamContain, // FIXME unused
|
||||||
|
"filterServicesByLabelValue": filterServicesByLabelValue, // FIXME unused
|
||||||
|
|
||||||
|
// Backend functions
|
||||||
|
"getWeight": getFuncServiceStringLabel(label.TraefikWeight, label.DefaultWeight),
|
||||||
|
"getProtocol": getFuncServiceStringLabel(label.TraefikProtocol, label.DefaultProtocol),
|
||||||
|
"getMaxConn": getMaxConn,
|
||||||
|
"getHealthCheck": getHealthCheck,
|
||||||
|
"getCircuitBreaker": getCircuitBreaker,
|
||||||
|
"getLoadBalancer": getLoadBalancer,
|
||||||
|
|
||||||
|
// Frontend Functions
|
||||||
|
"getPriority": getFuncServiceStringLabel(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
|
"getPassHostHeader": getFuncServiceStringLabel(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
|
"getPassTLSCert": getFuncBoolLabel(label.TraefikFrontendPassTLSCert, false),
|
||||||
|
"getEntryPoints": getFuncServiceSliceStringLabel(label.TraefikFrontendEntryPoints),
|
||||||
|
"getBasicAuth": getFuncServiceSliceStringLabel(label.TraefikFrontendAuthBasic),
|
||||||
|
"getWhitelistSourceRange": getFuncServiceSliceStringLabel(label.TraefikFrontendWhitelistSourceRange),
|
||||||
|
"getFrontendRules": getFuncServiceLabelWithPrefix(label.TraefikFrontendRule),
|
||||||
|
|
||||||
|
"getHeaders": getHeaders,
|
||||||
|
"getRedirect": getRedirect,
|
||||||
|
|
||||||
|
// SF Service Grouping
|
||||||
|
"getGroupedServices": getFuncServicesGroupedByLabel(traefikSFGroupName),
|
||||||
|
"getGroupedWeight": getFuncServiceStringLabel(traefikSFGroupWeight, "1"),
|
||||||
|
}
|
||||||
|
|
||||||
|
services, err := getClusterServices(sfClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
templateObjects := struct {
|
||||||
|
Services []ServiceItemExtended
|
||||||
|
}{
|
||||||
|
Services: services,
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.GetConfiguration(tmpl, sfFuncMap, templateObjects)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStateful(service ServiceItemExtended) bool {
|
||||||
|
return service.ServiceKind == "Stateful"
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStateless(service ServiceItemExtended) bool {
|
||||||
|
return service.ServiceKind == "Stateless"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBackendName(service ServiceItemExtended, partition PartitionItemExtended) string {
|
||||||
|
return provider.Normalize(service.Name + partition.PartitionInformation.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDefaultEndpoint(instance replicaInstance) string {
|
||||||
|
id, data := instance.GetReplicaData()
|
||||||
|
endpoint, err := getReplicaDefaultEndpoint(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("No default endpoint for replica %s in service %s endpointData: %s", id, data.Address)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReplicaDefaultEndpoint(replicaData *sf.ReplicaItemBase) (string, error) {
|
||||||
|
endpoints, err := decodeEndpointData(replicaData.Address)
|
||||||
|
if err != nil {
|
||||||
|
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 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 getServices(services []ServiceItemExtended, key string) map[string][]ServiceItemExtended {
|
||||||
|
result := map[string][]ServiceItemExtended{}
|
||||||
|
for _, service := range services {
|
||||||
|
if value, exists := service.Labels[key]; exists {
|
||||||
|
if matchingServices, hasKeyAlready := result[value]; hasKeyAlready {
|
||||||
|
result[value] = append(matchingServices, service)
|
||||||
|
} else {
|
||||||
|
result[value] = []ServiceItemExtended{service}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func doesAppParamContain(app sf.ApplicationItem, key, shouldContain string) bool {
|
||||||
|
value := getApplicationParameter(app, key)
|
||||||
|
return strings.Contains(value, shouldContain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterServicesByLabelValue(services []ServiceItemExtended, key, expectedValue string) []ServiceItemExtended {
|
||||||
|
var srvWithLabel []ServiceItemExtended
|
||||||
|
for _, service := range services {
|
||||||
|
value, exists := service.Labels[key]
|
||||||
|
if exists && value == expectedValue {
|
||||||
|
srvWithLabel = append(srvWithLabel, service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return srvWithLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeEndpointData(endpointData string) (map[string]string, error) {
|
||||||
|
var endpointsMap map[string]map[string]string
|
||||||
|
|
||||||
|
if endpointData == "" {
|
||||||
|
return nil, errors.New("endpoint data is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := json.Unmarshal([]byte(endpointData), &endpointsMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints, endpointsExist := endpointsMap["Endpoints"]
|
||||||
|
if !endpointsExist {
|
||||||
|
return nil, errors.New("endpoint doesn't exist in endpoint data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHeaders(service ServiceItemExtended) *types.Headers {
|
||||||
|
headers := &types.Headers{
|
||||||
|
CustomRequestHeaders: label.GetMapValue(service.Labels, label.TraefikFrontendRequestHeaders),
|
||||||
|
CustomResponseHeaders: label.GetMapValue(service.Labels, label.TraefikFrontendResponseHeaders),
|
||||||
|
SSLProxyHeaders: label.GetMapValue(service.Labels, label.TraefikFrontendSSLProxyHeaders),
|
||||||
|
AllowedHosts: label.GetSliceStringValue(service.Labels, label.TraefikFrontendAllowedHosts),
|
||||||
|
HostsProxyHeaders: label.GetSliceStringValue(service.Labels, label.TraefikFrontendHostsProxyHeaders),
|
||||||
|
STSSeconds: label.GetInt64Value(service.Labels, label.TraefikFrontendSTSSeconds, 0),
|
||||||
|
SSLRedirect: label.GetBoolValue(service.Labels, label.TraefikFrontendSSLRedirect, false),
|
||||||
|
SSLTemporaryRedirect: label.GetBoolValue(service.Labels, label.TraefikFrontendSSLTemporaryRedirect, false),
|
||||||
|
STSIncludeSubdomains: label.GetBoolValue(service.Labels, label.TraefikFrontendSTSIncludeSubdomains, false),
|
||||||
|
STSPreload: label.GetBoolValue(service.Labels, label.TraefikFrontendSTSPreload, false),
|
||||||
|
ForceSTSHeader: label.GetBoolValue(service.Labels, label.TraefikFrontendForceSTSHeader, false),
|
||||||
|
FrameDeny: label.GetBoolValue(service.Labels, label.TraefikFrontendFrameDeny, false),
|
||||||
|
ContentTypeNosniff: label.GetBoolValue(service.Labels, label.TraefikFrontendContentTypeNosniff, false),
|
||||||
|
BrowserXSSFilter: label.GetBoolValue(service.Labels, label.TraefikFrontendBrowserXSSFilter, false),
|
||||||
|
IsDevelopment: label.GetBoolValue(service.Labels, label.TraefikFrontendIsDevelopment, false),
|
||||||
|
SSLHost: label.GetStringValue(service.Labels, label.TraefikFrontendSSLHost, ""),
|
||||||
|
CustomFrameOptionsValue: label.GetStringValue(service.Labels, label.TraefikFrontendCustomFrameOptionsValue, ""),
|
||||||
|
ContentSecurityPolicy: label.GetStringValue(service.Labels, label.TraefikFrontendContentSecurityPolicy, ""),
|
||||||
|
PublicKey: label.GetStringValue(service.Labels, label.TraefikFrontendPublicKey, ""),
|
||||||
|
ReferrerPolicy: label.GetStringValue(service.Labels, label.TraefikFrontendReferrerPolicy, ""),
|
||||||
|
CustomBrowserXSSValue: label.GetStringValue(service.Labels, label.TraefikFrontendCustomBrowserXSSValue, ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !headers.HasSecureHeadersDefined() && !headers.HasCustomHeadersDefined() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRedirect(service ServiceItemExtended) *types.Redirect {
|
||||||
|
permanent := label.GetBoolValue(service.Labels, label.TraefikFrontendRedirectPermanent, false)
|
||||||
|
|
||||||
|
if label.Has(service.Labels, label.TraefikFrontendRedirectEntryPoint) {
|
||||||
|
return &types.Redirect{
|
||||||
|
EntryPoint: label.GetStringValue(service.Labels, label.TraefikFrontendRedirectEntryPoint, ""),
|
||||||
|
Permanent: permanent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if label.Has(service.Labels, label.TraefikFrontendRedirectRegex) &&
|
||||||
|
label.Has(service.Labels, label.TraefikFrontendRedirectReplacement) {
|
||||||
|
return &types.Redirect{
|
||||||
|
Regex: label.GetStringValue(service.Labels, label.TraefikFrontendRedirectRegex, ""),
|
||||||
|
Replacement: label.GetStringValue(service.Labels, label.TraefikFrontendRedirectReplacement, ""),
|
||||||
|
Permanent: permanent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMaxConn(service ServiceItemExtended) *types.MaxConn {
|
||||||
|
amount := label.GetInt64Value(service.Labels, label.TraefikBackendMaxConnAmount, math.MinInt64)
|
||||||
|
extractorFunc := label.GetStringValue(service.Labels, label.TraefikBackendMaxConnExtractorFunc, label.DefaultBackendMaxconnExtractorFunc)
|
||||||
|
|
||||||
|
if amount == math.MinInt64 || len(extractorFunc) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.MaxConn{
|
||||||
|
Amount: amount,
|
||||||
|
ExtractorFunc: extractorFunc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHealthCheck(service ServiceItemExtended) *types.HealthCheck {
|
||||||
|
path := label.GetStringValue(service.Labels, label.TraefikBackendHealthCheckPath, "")
|
||||||
|
if len(path) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
port := label.GetIntValue(service.Labels, label.TraefikBackendHealthCheckPort, label.DefaultBackendHealthCheckPort)
|
||||||
|
interval := label.GetStringValue(service.Labels, label.TraefikBackendHealthCheckInterval, "")
|
||||||
|
|
||||||
|
return &types.HealthCheck{
|
||||||
|
Path: path,
|
||||||
|
Port: port,
|
||||||
|
Interval: interval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCircuitBreaker(service ServiceItemExtended) *types.CircuitBreaker {
|
||||||
|
circuitBreaker := label.GetStringValue(service.Labels, label.TraefikBackendCircuitBreakerExpression, "")
|
||||||
|
if len(circuitBreaker) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &types.CircuitBreaker{Expression: circuitBreaker}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLoadBalancer(service ServiceItemExtended) *types.LoadBalancer {
|
||||||
|
if !label.HasPrefix(service.Labels, label.TraefikBackendLoadBalancer) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
method := label.GetStringValue(service.Labels, label.TraefikBackendLoadBalancerMethod, label.DefaultBackendLoadBalancerMethod)
|
||||||
|
|
||||||
|
lb := &types.LoadBalancer{
|
||||||
|
Method: method,
|
||||||
|
Sticky: getSticky(service),
|
||||||
|
}
|
||||||
|
|
||||||
|
if label.GetBoolValue(service.Labels, label.TraefikBackendLoadBalancerStickiness, false) {
|
||||||
|
cookieName := label.GetStringValue(service.Labels, label.TraefikBackendLoadBalancerStickinessCookieName, label.DefaultBackendLoadbalancerStickinessCookieName)
|
||||||
|
lb.Stickiness = &types.Stickiness{CookieName: cookieName}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lb
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Deprecated
|
||||||
|
// replaced by Stickiness
|
||||||
|
// Deprecated
|
||||||
|
func getSticky(service ServiceItemExtended) bool {
|
||||||
|
if label.Has(service.Labels, label.TraefikBackendLoadBalancerSticky) {
|
||||||
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", label.TraefikBackendLoadBalancerSticky, label.TraefikBackendLoadBalancerStickiness)
|
||||||
|
}
|
||||||
|
|
||||||
|
return label.GetBoolValue(service.Labels, label.TraefikBackendLoadBalancerSticky, false)
|
||||||
|
}
|
63
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_labelfuncs.go
generated
vendored
Normal file
63
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_labelfuncs.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package servicefabric
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/provider/label"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SF Specific Traefik Labels
|
||||||
|
const (
|
||||||
|
traefikSFGroupName = "traefik.servicefabric.groupname"
|
||||||
|
traefikSFGroupWeight = "traefik.servicefabric.groupweight"
|
||||||
|
traefikSFEnableLabelOverrides = "traefik.servicefabric.enablelabeloverrides"
|
||||||
|
traefikSFEnableLabelOverridesDefault = true
|
||||||
|
)
|
||||||
|
|
||||||
|
func getFuncBoolLabel(labelName string, defaultValue bool) func(service ServiceItemExtended) bool {
|
||||||
|
return func(service ServiceItemExtended) bool {
|
||||||
|
return label.GetBoolValue(service.Labels, labelName, defaultValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getServiceStringLabel(service ServiceItemExtended, labelName string, defaultValue string) string {
|
||||||
|
return label.GetStringValue(service.Labels, labelName, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFuncServiceStringLabel(labelName string, defaultValue string) func(service ServiceItemExtended) string {
|
||||||
|
return func(service ServiceItemExtended) string {
|
||||||
|
return label.GetStringValue(service.Labels, labelName, defaultValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFuncServiceSliceStringLabel(labelName string) func(service ServiceItemExtended) []string {
|
||||||
|
return func(service ServiceItemExtended) []string {
|
||||||
|
return label.GetSliceStringValue(service.Labels, labelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasService(service ServiceItemExtended, labelName string) bool {
|
||||||
|
return label.Has(service.Labels, labelName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFuncServiceLabelWithPrefix(labelName string) func(service ServiceItemExtended) map[string]string {
|
||||||
|
return func(service ServiceItemExtended) map[string]string {
|
||||||
|
return getServiceLabelsWithPrefix(service, labelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFuncServicesGroupedByLabel(labelName string) func(services []ServiceItemExtended) map[string][]ServiceItemExtended {
|
||||||
|
return func(services []ServiceItemExtended) map[string][]ServiceItemExtended {
|
||||||
|
return getServices(services, 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
|
||||||
|
}
|
185
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_tmpl.go
generated
vendored
185
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric_tmpl.go
generated
vendored
|
@ -1,52 +1,59 @@
|
||||||
package servicefabric
|
package servicefabric
|
||||||
|
|
||||||
const tmpl = `
|
const tmpl = `
|
||||||
{{$groupedServiceMap := getServices .Services "backend.group.name"}}
|
|
||||||
[backends]
|
[backends]
|
||||||
{{range $aggName, $aggServices := $groupedServiceMap }}
|
{{range $aggName, $aggServices := getGroupedServices .Services }}
|
||||||
[backends."{{ $aggName }}"]
|
[backends."{{ $aggName }}"]
|
||||||
{{range $service := $aggServices }}
|
{{range $service := $aggServices }}
|
||||||
{{range $partition := $service.Partitions }}
|
{{range $partition := $service.Partitions }}
|
||||||
{{range $instance := $partition.Instances }}
|
{{range $instance := $partition.Instances }}
|
||||||
[backends."{{ $aggName }}".servers."{{ $service.ID }}-{{ $instance.ID }}"]
|
[backends."{{ $aggName }}".servers."{{ $service.ID }}-{{ $instance.ID }}"]
|
||||||
url = "{{ getDefaultEndpoint $instance }}"
|
url = "{{ getDefaultEndpoint $instance }}"
|
||||||
weight = {{getLabelValue $service "backend.group.weight" "1"}}
|
weight = {{ getGroupedWeight $service }}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range $service := .Services }}
|
{{range $service := .Services }}
|
||||||
|
{{if isEnabled $service }}
|
||||||
{{range $partition := $service.Partitions }}
|
{{range $partition := $service.Partitions }}
|
||||||
{{if eq $partition.ServiceKind "Stateless"}}
|
|
||||||
[backends."{{$service.Name}}"]
|
{{if isStateless $service }}
|
||||||
[backends."{{$service.Name}}".LoadBalancer]
|
|
||||||
{{if hasLabel $service "backend.loadbalancer.method"}}
|
{{ $backendName := $service.Name }}
|
||||||
method = "{{getLabelValue $service "backend.loadbalancer.method" "" }}"
|
[backends."{{ $backendName }}"]
|
||||||
{{else}}
|
|
||||||
method = "drr"
|
{{ $circuitBreaker := getCircuitBreaker $service }}
|
||||||
|
{{if $circuitBreaker }}
|
||||||
|
[backends."{{ $backendName }}".circuitBreaker]
|
||||||
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "backend.healthcheck"}}
|
{{ $loadBalancer := getLoadBalancer $service }}
|
||||||
[backends."{{$service.Name}}".healthcheck]
|
{{if $loadBalancer }}
|
||||||
path = "{{getLabelValue $service "backend.healthcheck" ""}}"
|
[backends."{{ $backendName }}".loadBalancer]
|
||||||
interval = "{{getLabelValue $service "backend.healthcheck.interval" "10s"}}"
|
method = "{{ $loadBalancer.Method }}"
|
||||||
|
sticky = {{ $loadBalancer.Sticky }}
|
||||||
|
{{if $loadBalancer.Stickiness }}
|
||||||
|
[backends."{{ $backendName }}".loadBalancer.stickiness]
|
||||||
|
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "backend.loadbalancer.stickiness"}}
|
{{ $maxConn := getMaxConn $service }}
|
||||||
[backends."{{$service.Name}}".LoadBalancer.stickiness]
|
{{if $maxConn }}
|
||||||
|
[backends."{{ $backendName }}".maxConn]
|
||||||
|
extractorFunc = "{{ $maxConn.ExtractorFunc }}"
|
||||||
|
amount = {{ $maxConn.Amount }}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "backend.circuitbreaker"}}
|
{{ $healthCheck := getHealthCheck $service }}
|
||||||
[backends."{{$service.Name}}".circuitbreaker]
|
{{if $healthCheck }}
|
||||||
expression = "{{getLabelValue $service "backend.circuitbreaker" ""}}"
|
[backends."{{ $backendName }}".healthCheck]
|
||||||
{{end}}
|
path = "{{ $healthCheck.Path }}"
|
||||||
|
port = {{ $healthCheck.Port }}
|
||||||
{{if hasLabel $service "backend.maxconn.amount"}}
|
interval = "{{ $healthCheck.Interval }}"
|
||||||
[backends."{{$service.Name}}".maxconn]
|
|
||||||
amount = {{getLabelValue $service "backend.maxconn.amount" ""}}
|
|
||||||
{{if hasLabel $service "backend.maxconn.extractorfunc"}}
|
|
||||||
extractorfunc = "{{getLabelValue $service "backend.maxconn.extractorfunc" ""}}"
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range $instance := $partition.Instances}}
|
{{range $instance := $partition.Instances}}
|
||||||
|
@ -54,11 +61,12 @@ const tmpl = `
|
||||||
url = "{{ getDefaultEndpoint $instance }}"
|
url = "{{ getDefaultEndpoint $instance }}"
|
||||||
weight = {{ getLabelValue $service "backend.weight" "1" }}
|
weight = {{ getLabelValue $service "backend.weight" "1" }}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else if eq $partition.ServiceKind "Stateful"}}
|
|
||||||
|
{{else if isStateful $service}}
|
||||||
|
|
||||||
{{range $replica := $partition.Replicas}}
|
{{range $replica := $partition.Replicas}}
|
||||||
{{if isPrimary $replica}}
|
{{if isPrimary $replica}}
|
||||||
|
{{ $backendName := getBackendName $service $partition }}
|
||||||
{{$backendName := getBackendName $service.Name $partition}}
|
|
||||||
[backends."{{ $backendName }}".servers."{{ $replica.ID }}"]
|
[backends."{{ $backendName }}".servers."{{ $replica.ID }}"]
|
||||||
url = "{{ getDefaultEndpoint $replica }}"
|
url = "{{ getDefaultEndpoint $replica }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
@ -66,75 +74,136 @@ const tmpl = `
|
||||||
[backends."{{$backendName}}".LoadBalancer]
|
[backends."{{$backendName}}".LoadBalancer]
|
||||||
method = "drr"
|
method = "drr"
|
||||||
|
|
||||||
[backends."{{$backendName}}".circuitbreaker]
|
{{end}}
|
||||||
expression = "NetworkErrorRatio() > 0.5"
|
{{end}}
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
[frontends]
|
[frontends]
|
||||||
{{range $groupName, $groupServices := $groupedServiceMap}}
|
{{range $groupName, $groupServices := getGroupedServices .Services }}
|
||||||
{{ $service := index $groupServices 0 }}
|
{{ $service := index $groupServices 0 }}
|
||||||
[frontends."{{ $groupName }}"]
|
[frontends."{{ $groupName }}"]
|
||||||
backend = "{{ $groupName }}"
|
backend = "{{ $groupName }}"
|
||||||
|
priority = 50
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.priority"}}
|
{{range $key, $value := getFrontendRules $service }}
|
||||||
priority = 100
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{range $key, $value := getLabelsWithPrefix $service "frontend.rule"}}
|
|
||||||
[frontends."{{ $groupName }}".routes."{{ $key }}"]
|
[frontends."{{ $groupName }}".routes."{{ $key }}"]
|
||||||
rule = "{{ $value }}"
|
rule = "{{ $value }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range $service := .Services }}
|
{{range $service := .Services }}
|
||||||
{{if isExposed $service}}
|
{{if isEnabled $service }}
|
||||||
{{if eq $service.ServiceKind "Stateless"}}
|
{{ $frontendName := $service.Name }}
|
||||||
|
|
||||||
[frontends."{{$service.Name}}"]
|
{{if isStateless $service }}
|
||||||
|
|
||||||
|
[frontends."frontend-{{ $frontendName }}"]
|
||||||
backend = "{{ $service.Name }}"
|
backend = "{{ $service.Name }}"
|
||||||
|
passHostHeader = {{ getPassHostHeader $service }}
|
||||||
|
passTLSCert = {{ getPassTLSCert $service }}
|
||||||
|
priority = {{ getPriority $service }}
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.passHostHeader"}}
|
{{ $entryPoints := getEntryPoints $service }}
|
||||||
passHostHeader = {{getLabelValue $service "frontend.passHostHeader" ""}}
|
{{if $entryPoints }}
|
||||||
|
entryPoints = [{{range $entryPoints }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.whitelistSourceRange"}}
|
{{ $whitelistSourceRange := getWhitelistSourceRange $service }}
|
||||||
whitelistSourceRange = {{getLabelValue $service "frontend.whitelistSourceRange" ""}}
|
{{if $whitelistSourceRange }}
|
||||||
|
whitelistSourceRange = [{{range $whitelistSourceRange }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.priority"}}
|
{{ $basicAuth := getBasicAuth $service }}
|
||||||
priority = {{getLabelValue $service "frontend.priority" ""}}
|
{{if $basicAuth }}
|
||||||
|
basicAuth = [{{range $basicAuth }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.basicAuth"}}
|
{{ $headers := getHeaders $service }}
|
||||||
basicAuth = {{getLabelValue $service "frontend.basicAuth" ""}}
|
{{if $headers }}
|
||||||
|
[frontends."frontend-{{ $frontendName }}".headers]
|
||||||
|
SSLRedirect = {{ $headers.SSLRedirect }}
|
||||||
|
SSLTemporaryRedirect = {{ $headers.SSLTemporaryRedirect }}
|
||||||
|
SSLHost = "{{ $headers.SSLHost }}"
|
||||||
|
STSSeconds = {{ $headers.STSSeconds }}
|
||||||
|
STSIncludeSubdomains = {{ $headers.STSIncludeSubdomains }}
|
||||||
|
STSPreload = {{ $headers.STSPreload }}
|
||||||
|
ForceSTSHeader = {{ $headers.ForceSTSHeader }}
|
||||||
|
FrameDeny = {{ $headers.FrameDeny }}
|
||||||
|
CustomFrameOptionsValue = "{{ $headers.CustomFrameOptionsValue }}"
|
||||||
|
ContentTypeNosniff = {{ $headers.ContentTypeNosniff }}
|
||||||
|
BrowserXSSFilter = {{ $headers.BrowserXSSFilter }}
|
||||||
|
CustomBrowserXSSValue = "{{ $headers.CustomBrowserXSSValue }}"
|
||||||
|
ContentSecurityPolicy = "{{ $headers.ContentSecurityPolicy }}"
|
||||||
|
PublicKey = "{{ $headers.PublicKey }}"
|
||||||
|
ReferrerPolicy = "{{ $headers.ReferrerPolicy }}"
|
||||||
|
IsDevelopment = {{ $headers.IsDevelopment }}
|
||||||
|
|
||||||
|
{{if $headers.AllowedHosts }}
|
||||||
|
AllowedHosts = [{{range $headers.AllowedHosts }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.entryPoints"}}
|
{{if $headers.HostsProxyHeaders }}
|
||||||
entryPoints = {{getLabelValue $service "frontend.entryPoints" ""}}
|
HostsProxyHeaders = [{{range $headers.HostsProxyHeaders }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range $key, $value := getLabelsWithPrefix $service "frontend.rule"}}
|
{{if $headers.CustomRequestHeaders }}
|
||||||
[frontends."{{$service.Name}}".routes."{{$key}}"]
|
[frontends."frontend-{{ $frontendName }}".headers.customRequestHeaders]
|
||||||
|
{{range $k, $v := $headers.CustomRequestHeaders }}
|
||||||
|
{{$k}} = "{{$v}}"
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $headers.CustomResponseHeaders }}
|
||||||
|
[frontends."frontend-{{ $frontendName }}".headers.customResponseHeaders]
|
||||||
|
{{range $k, $v := $headers.CustomResponseHeaders }}
|
||||||
|
{{$k}} = "{{$v}}"
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $headers.SSLProxyHeaders }}
|
||||||
|
[frontends."frontend-{{ $frontendName }}".headers.SSLProxyHeaders]
|
||||||
|
{{range $k, $v := $headers.SSLProxyHeaders }}
|
||||||
|
{{$k}} = "{{$v}}"
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{range $key, $value := getFrontendRules $service }}
|
||||||
|
[frontends."frontend-{{ $frontendName }}".routes."{{ $key }}"]
|
||||||
rule = "{{ $value }}"
|
rule = "{{ $value }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{else if eq $service.ServiceKind "Stateful"}}
|
{{else if isStateful $service}}
|
||||||
|
|
||||||
{{range $partition := $service.Partitions }}
|
{{range $partition := $service.Partitions }}
|
||||||
{{ $partitionId := $partition.PartitionInformation.ID }}
|
{{ $partitionId := $partition.PartitionInformation.ID }}
|
||||||
|
|
||||||
{{if hasLabel $service "frontend.rule" }}
|
{{if hasLabel $service "frontend.rule" }}
|
||||||
[frontends."{{ $service.Name }}/{{ $partitionId }}"]
|
[frontends."{{ $service.Name }}/{{ $partitionId }}"]
|
||||||
backend = "{{ getBackendName $service.Name $partition }}"
|
backend = "{{ getBackendName $service.Name $partition }}"
|
||||||
|
|
||||||
[frontends."{{ $service.Name }}/{{ $partitionId }}".routes.default]
|
[frontends."{{ $service.Name }}/{{ $partitionId }}".routes.default]
|
||||||
rule = {{ getLabelValue $service "frontend.rule.partition.$partitionId" "" }}
|
rule = {{ getLabelValue $service "frontend.rule.partition.$partitionId" "" }}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
`
|
`
|
||||||
|
|
5
vendor/github.com/containous/traefik-extra-service-fabric/types.go
generated
vendored
5
vendor/github.com/containous/traefik-extra-service-fabric/types.go
generated
vendored
|
@ -9,8 +9,6 @@ import (
|
||||||
// it belongs too and the replicas/partitions
|
// it belongs too and the replicas/partitions
|
||||||
type ServiceItemExtended struct {
|
type ServiceItemExtended struct {
|
||||||
sf.ServiceItem
|
sf.ServiceItem
|
||||||
HasHTTPEndpoint bool
|
|
||||||
IsHealthy bool
|
|
||||||
Application sf.ApplicationItem
|
Application sf.ApplicationItem
|
||||||
Partitions []PartitionItemExtended
|
Partitions []PartitionItemExtended
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
|
@ -32,8 +30,9 @@ type sfClient interface {
|
||||||
GetPartitions(appName, serviceName string) (*sf.PartitionItemsPage, error)
|
GetPartitions(appName, serviceName string) (*sf.PartitionItemsPage, error)
|
||||||
GetReplicas(appName, serviceName, partitionName string) (*sf.ReplicaItemsPage, error)
|
GetReplicas(appName, serviceName, partitionName string) (*sf.ReplicaItemsPage, error)
|
||||||
GetInstances(appName, serviceName, partitionName string) (*sf.InstanceItemsPage, error)
|
GetInstances(appName, serviceName, partitionName string) (*sf.InstanceItemsPage, error)
|
||||||
GetServiceExtension(appType, applicationVersion, serviceTypeName, extensionKey string, response interface{}) error
|
GetServiceExtensionMap(service *sf.ServiceItem, app *sf.ApplicationItem, extensionKey string) (map[string]string, error)
|
||||||
GetServiceLabels(service *sf.ServiceItem, app *sf.ApplicationItem, prefix string) (map[string]string, error)
|
GetServiceLabels(service *sf.ServiceItem, app *sf.ApplicationItem, prefix string) (map[string]string, error)
|
||||||
|
GetProperties(name string) (bool, map[string]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// replicaInstance interface provides a unified interface
|
// replicaInstance interface provides a unified interface
|
||||||
|
|
24
vendor/github.com/jjcollinge/servicefabric/servicefabric.go
generated
vendored
24
vendor/github.com/jjcollinge/servicefabric/servicefabric.go
generated
vendored
|
@ -219,8 +219,30 @@ func (c Client) GetServiceExtension(appType, applicationVersion, serviceTypeName
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetServiceExtensionMap returns all the extension xml specified
|
||||||
|
// in a Service's manifest file into (which must conform to ServiceExtensionLabels)
|
||||||
|
// a map[string]string
|
||||||
|
func (c Client) GetServiceExtensionMap(service *ServiceItem, app *ApplicationItem, extensionKey string) (map[string]string, error) {
|
||||||
|
extensionData := ServiceExtensionLabels{}
|
||||||
|
err := c.GetServiceExtension(app.TypeName, app.TypeVersion, service.TypeName, extensionKey, &extensionData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := map[string]string{}
|
||||||
|
if extensionData.Label != nil {
|
||||||
|
for _, label := range extensionData.Label {
|
||||||
|
labels[label.Key] = label.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetProperties uses the Property Manager API to retrieve
|
// GetProperties uses the Property Manager API to retrieve
|
||||||
// string properties from a name as a dictionary
|
// string properties from a name as a dictionary
|
||||||
|
// Property name is the path to the properties you would like to list.
|
||||||
|
// for example a serviceID
|
||||||
func (c Client) GetProperties(name string) (bool, map[string]string, error) {
|
func (c Client) GetProperties(name string) (bool, map[string]string, error) {
|
||||||
nameExists, err := c.nameExists(name)
|
nameExists, err := c.nameExists(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -264,6 +286,8 @@ func (c Client) GetProperties(name string) (bool, map[string]string, error) {
|
||||||
|
|
||||||
// GetServiceLabels add labels from service manifest extensions and properties manager
|
// GetServiceLabels add labels from service manifest extensions and properties manager
|
||||||
// expects extension xml in <Label key="key">value</Label>
|
// expects extension xml in <Label key="key">value</Label>
|
||||||
|
//
|
||||||
|
// Deprecated: Use GetProperties and GetServiceExtensionMap instead.
|
||||||
func (c Client) GetServiceLabels(service *ServiceItem, app *ApplicationItem, prefix string) (map[string]string, error) {
|
func (c Client) GetServiceLabels(service *ServiceItem, app *ApplicationItem, prefix string) (map[string]string, error) {
|
||||||
extensionData := ServiceExtensionLabels{}
|
extensionData := ServiceExtensionLabels{}
|
||||||
err := c.GetServiceExtension(app.TypeName, app.TypeVersion, service.TypeName, prefix, &extensionData)
|
err := c.GetServiceExtension(app.TypeName, app.TypeVersion, service.TypeName, prefix, &extensionData)
|
||||||
|
|
Loading…
Reference in a new issue