Skip to content

Commit

Permalink
Fix the "supress health checks when only one backing service" logic
Browse files Browse the repository at this point in the history
Previously we had attempted to suppress the health checks, but it was looking at the endpoints of the service, not the servers that back the route. The problem is that if we just look at endpoints, then if a route has two backing services, each with one endpoint, we would incorrectly suppress the health checks.

This is the third attempt.  I had missed a case in the last one, so now the logic is moved to be computed and recorded by the router controller, but used in the template.

Fixes bug 1507664 (https://bugzilla.redhat.com/show_bug.cgi?id=1507664)
  • Loading branch information
knobunc committed Nov 2, 2017
1 parent e4ac5b0 commit 8cb7b95
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 18 deletions.
6 changes: 2 additions & 4 deletions images/router/haproxy/conf/haproxy-config.template
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,8 @@ backend be_secure:{{$cfgIdx}}
{{- else if or (eq $cfg.TLSTermination "") (eq $cfg.TLSTermination "edge") }}
{{- end }}{{/* end type specific options*/}}

{{- if not $endpoint.NoHealthCheck }} check inter {{firstMatch $timeSpecPattern (index $cfg.Annotations "router.openshift.io/haproxy.health.check.interval") (env "ROUTER_BACKEND_CHECK_INTERVAL") "5000ms"}}
{{- if and (not $endpoint.NoHealthCheck) (gt $cfg.ActiveEndpoints 1) }} check inter {{firstMatch $timeSpecPattern (index $cfg.Annotations "router.openshift.io/haproxy.health.check.interval") (env "ROUTER_BACKEND_CHECK_INTERVAL") "5000ms"}}
{{- end }}{{/* end else no health check */}}


{{- end }}{{/* end if cg.TLSTermination */}}
{{- end }}{{/* end range processEndpointsForAlias */}}
{{- end }}{{/* end get serviceUnit from its name */}}
Expand Down Expand Up @@ -464,7 +462,7 @@ backend be_tcp:{{$cfgIdx}}
{{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }}
{{- range $idx, $endpoint := processEndpointsForAlias $cfg $serviceUnit (env "ROUTER_BACKEND_PROCESS_ENDPOINTS" "") }}
server {{$endpoint.ID}} {{$endpoint.IP}}:{{$endpoint.Port}} weight {{$weight}}
{{- if not $endpoint.NoHealthCheck }} check inter {{firstMatch $timeSpecPattern (index $cfg.Annotations "router.openshift.io/haproxy.health.check.interval") (env "ROUTER_BACKEND_CHECK_INTERVAL") "5000ms"}}
{{- if and (not $endpoint.NoHealthCheck) (gt $cfg.ActiveEndpoints 1) }} check inter {{firstMatch $timeSpecPattern (index $cfg.Annotations "router.openshift.io/haproxy.health.check.interval") (env "ROUTER_BACKEND_CHECK_INTERVAL") "5000ms"}}
{{- end }}{{/* end else no health check */}}
{{- end }}{{/* end range processEndpointsForAlias */}}
{{- end }}{{/* end get ServiceUnit from serviceUnitName */}}
Expand Down
52 changes: 38 additions & 14 deletions pkg/router/template/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@ func (r *templateRouter) writeConfig() error {
// called here to make sure we have the actual number of endpoints.
cfg.ServiceUnitNames = r.calculateServiceWeights(cfg.ServiceUnits)

// Calculate the number of active endpoints for the route.
cfg.ActiveEndpoints = r.getActiveEndpoints(cfg.ServiceUnits)

cfg.Status = ServiceAliasConfigStatusSaved
r.state[k] = cfg
}
Expand Down Expand Up @@ -877,28 +880,49 @@ func getServiceUnits(route *routeapi.Route) map[string]int32 {

// get the weight and number of endpoints for each service
key := endpointsKeyFromParts(route.Namespace, route.Spec.To.Name)
serviceUnits[key] = 0
if route.Spec.To.Weight != nil {
serviceUnits[key] = int32(*route.Spec.To.Weight)
}
if serviceUnits[key] < 0 || serviceUnits[key] > 256 {
serviceUnits[key] = 0
}
serviceUnits[key] = getServiceUnitWeight(route.Spec.To.Weight)

for _, svc := range route.Spec.AlternateBackends {
key = endpointsKeyFromParts(route.Namespace, svc.Name)
serviceUnits[key] = 0
if svc.Weight != nil {
serviceUnits[key] = int32(*svc.Weight)
}
if serviceUnits[key] < 0 || serviceUnits[key] > 256 {
serviceUnits[key] = 0
}
serviceUnits[key] = getServiceUnitWeight(svc.Weight)
}

return serviceUnits
}

// getServiceUnitWeight takes a reference to a weight and returns its value or the default.
// It also checks that it is in the correct range.
func getServiceUnitWeight(weightRef *int32) int32 {
// Default to 1 if there is no weight
var weight int32 = 1
if weightRef != nil {
weight = *weightRef
}

// Do a bounds check
if weight < 0 {
weight = 0
} else if weight > 256 {
weight = 256
}

return weight
}

// getActiveEndpoints calculates the number of endpoints that are not associated
// with service units with a zero weight and returns the count.
func (r *templateRouter) getActiveEndpoints(serviceUnits map[string]int32) int {
var activeEndpoints int32 = 0

for key, weight := range serviceUnits {
if weight > 0 {
activeEndpoints += r.numberOfEndpoints(key)
}
}

return int(activeEndpoints)
}

// calculateServiceWeights returns a map of service keys to their weights.
// Each service gets (weight/sum_of_weights) fraction of the requests.
// For each service, the requests are distributed among the endpoints.
Expand Down
3 changes: 3 additions & 0 deletions pkg/router/template/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type ServiceAliasConfig struct {

// ActiveServiceUnits is a count of the service units with a non-zero weight
ActiveServiceUnits int

// ActiveEndpoints is a count of the route endpoints that are part of a service unit with a non-zero weight
ActiveEndpoints int
}

type ServiceAliasConfigStatus string
Expand Down

0 comments on commit 8cb7b95

Please sign in to comment.