mprove Rancher provider functionality:
- Improves default filtering behavior to filter by container health/healthState - Optionally allows filtering by service health/healthState - Allows configuration of refresh interval
This commit is contained in:
parent
e2fdc27d64
commit
44db6e9290
5 changed files with 205 additions and 22 deletions
13
docs/toml.md
13
docs/toml.md
|
@ -1604,6 +1604,12 @@ domain = "rancher.localhost"
|
|||
#
|
||||
Watch = true
|
||||
|
||||
# Polling interval (in seconds)
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
RefreshSeconds = 15
|
||||
|
||||
# Expose Rancher services by default in traefik
|
||||
#
|
||||
# Optional
|
||||
|
@ -1611,6 +1617,13 @@ Watch = true
|
|||
#
|
||||
ExposedByDefault = false
|
||||
|
||||
# Filter services with unhealthy states and health states
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
EnableServiceHealthFilter = false
|
||||
|
||||
# Endpoint to use when connecting to Rancher
|
||||
#
|
||||
# Required
|
||||
|
|
|
@ -21,11 +21,6 @@ import (
|
|||
rancher "github.com/rancher/go-rancher/client"
|
||||
)
|
||||
|
||||
const (
|
||||
// RancherDefaultWatchTime is the duration of the interval when polling rancher
|
||||
RancherDefaultWatchTime = 15 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
withoutPagination *rancher.ListOpts
|
||||
)
|
||||
|
@ -40,6 +35,8 @@ type Provider struct {
|
|||
SecretKey string `description:"Rancher server Secret Key."`
|
||||
ExposedByDefault bool `description:"Expose Services by default"`
|
||||
Domain string `description:"Default domain used"`
|
||||
RefreshSeconds int `description:"Polling interval (in seconds)"`
|
||||
EnableServiceHealthFilter bool `description:"Filter services with unhealthy states and health states."`
|
||||
}
|
||||
|
||||
type rancherData struct {
|
||||
|
@ -47,6 +44,7 @@ type rancherData struct {
|
|||
Labels map[string]string // List of labels set to container or service
|
||||
Containers []string
|
||||
Health string
|
||||
State string
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -56,7 +54,7 @@ func init() {
|
|||
}
|
||||
|
||||
func (r rancherData) String() string {
|
||||
return fmt.Sprintf("{name:%s, labels:%v, containers: %v, health: %s}", r.Name, r.Labels, r.Containers, r.Health)
|
||||
return fmt.Sprintf("{name:%s, labels:%v, containers: %v, health: %s, state: %s}", r.Name, r.Labels, r.Containers, r.Health, r.State)
|
||||
}
|
||||
|
||||
// Frontend Labels
|
||||
|
@ -261,7 +259,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
|||
|
||||
if p.Watch {
|
||||
_, cancel := context.WithCancel(ctx)
|
||||
ticker := time.NewTicker(RancherDefaultWatchTime)
|
||||
ticker := time.NewTicker(time.Second * time.Duration(p.RefreshSeconds))
|
||||
pool.Go(func(stop chan bool) {
|
||||
for {
|
||||
select {
|
||||
|
@ -384,6 +382,7 @@ func parseRancherData(environments []*rancher.Environment, services []*rancher.S
|
|||
rancherData := rancherData{
|
||||
Name: environment.Name + "/" + service.Name,
|
||||
Health: service.HealthState,
|
||||
State: service.State,
|
||||
Labels: make(map[string]string),
|
||||
Containers: []string{},
|
||||
}
|
||||
|
@ -393,13 +392,10 @@ func parseRancherData(environments []*rancher.Environment, services []*rancher.S
|
|||
}
|
||||
|
||||
for _, container := range containers {
|
||||
for key, value := range container.Labels {
|
||||
|
||||
if key == "io.rancher.stack_service.name" && value == rancherData.Name {
|
||||
if container.Labels["io.rancher.stack_service.name"] == rancherData.Name && containerFilter(container) {
|
||||
rancherData.Containers = append(rancherData.Containers, container.PrimaryIpAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
rancherDataList = append(rancherDataList, rancherData)
|
||||
}
|
||||
}
|
||||
|
@ -463,6 +459,20 @@ func (p *Provider) loadRancherConfig(services []rancherData) *types.Configuratio
|
|||
|
||||
}
|
||||
|
||||
func containerFilter(container *rancher.Container) bool {
|
||||
if container.HealthState != "" && container.HealthState != "healthy" && container.HealthState != "updating-healthy" {
|
||||
log.Debugf("Filtering container %s with healthState of %s", container.Name, container.HealthState)
|
||||
return false
|
||||
}
|
||||
|
||||
if container.State != "" && container.State != "running" && container.State != "updating-running" {
|
||||
log.Debugf("Filtering container %s with state of %s", container.Name, container.State)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *Provider) serviceFilter(service rancherData) bool {
|
||||
|
||||
if service.Labels["traefik.port"] == "" {
|
||||
|
@ -475,11 +485,20 @@ func (p *Provider) serviceFilter(service rancherData) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if service.Health != "" && service.Health != "healthy" {
|
||||
log.Debugf("Filtering unhealthy or starting service %s", service.Name)
|
||||
// Only filter services by Health (HealthState) and State if EnableServiceHealthFilter is true
|
||||
if p.EnableServiceHealthFilter {
|
||||
|
||||
if service.Health != "" && service.Health != "healthy" && service.Health != "updating-healthy" {
|
||||
log.Debugf("Filtering service %s with healthState of %s", service.Name, service.Health)
|
||||
return false
|
||||
}
|
||||
|
||||
if service.State != "" && service.State != "active" && service.State != "updating-active" && service.State != "upgraded" {
|
||||
log.Debugf("Filtering service %s with state of %s", service.Name, service.State)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,148 @@
|
|||
package rancher
|
||||
|
||||
import (
|
||||
"github.com/containous/traefik/types"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/types"
|
||||
rancher "github.com/rancher/go-rancher/client"
|
||||
)
|
||||
|
||||
func TestRancherServiceFilter(t *testing.T) {
|
||||
provider := &Provider{
|
||||
Domain: "rancher.localhost",
|
||||
EnableServiceHealthFilter: true,
|
||||
}
|
||||
|
||||
services := []struct {
|
||||
service rancherData
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
service: rancherData{
|
||||
Labels: map[string]string{
|
||||
"traefik.enable": "true",
|
||||
},
|
||||
Health: "healthy",
|
||||
State: "active",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "80",
|
||||
"traefik.enable": "false",
|
||||
},
|
||||
Health: "healthy",
|
||||
State: "active",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "80",
|
||||
"traefik.enable": "true",
|
||||
},
|
||||
Health: "unhealthy",
|
||||
State: "active",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "80",
|
||||
"traefik.enable": "true",
|
||||
},
|
||||
Health: "healthy",
|
||||
State: "inactive",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "80",
|
||||
"traefik.enable": "true",
|
||||
},
|
||||
Health: "healthy",
|
||||
State: "active",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "80",
|
||||
"traefik.enable": "true",
|
||||
},
|
||||
Health: "healthy",
|
||||
State: "upgraded",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range services {
|
||||
actual := provider.serviceFilter(e.service)
|
||||
if actual != e.expected {
|
||||
t.Fatalf("expected %t, got %t", e.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRancherContainerFilter(t *testing.T) {
|
||||
containers := []struct {
|
||||
container *rancher.Container
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
container: &rancher.Container{
|
||||
HealthState: "unhealthy",
|
||||
State: "running",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
container: &rancher.Container{
|
||||
HealthState: "healthy",
|
||||
State: "stopped",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
container: &rancher.Container{
|
||||
State: "stopped",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
container: &rancher.Container{
|
||||
HealthState: "healthy",
|
||||
State: "running",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
container: &rancher.Container{
|
||||
HealthState: "updating-healthy",
|
||||
State: "updating-running",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range containers {
|
||||
actual := containerFilter(e.container)
|
||||
if actual != e.expected {
|
||||
t.Fatalf("expected %t, got %t", e.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRancherGetFrontendName(t *testing.T) {
|
||||
provider := &Provider{
|
||||
Domain: "rancher.localhost",
|
||||
|
|
|
@ -446,6 +446,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
|||
var defaultRancher rancher.Provider
|
||||
defaultRancher.Watch = true
|
||||
defaultRancher.ExposedByDefault = true
|
||||
defaultRancher.RefreshSeconds = 15
|
||||
defaultRancher.EnableServiceHealthFilter = false
|
||||
|
||||
// default DynamoDB
|
||||
var defaultDynamoDB dynamodb.Provider
|
||||
|
|
|
@ -1046,6 +1046,12 @@
|
|||
#
|
||||
# Watch = true
|
||||
|
||||
# Polling interval (in seconds)
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
# RefreshSeconds = 15
|
||||
|
||||
# Expose Rancher services by default in traefik
|
||||
#
|
||||
# Optional
|
||||
|
@ -1053,6 +1059,13 @@
|
|||
#
|
||||
# ExposedByDefault = false
|
||||
|
||||
# Filter services with unhealthy states and health states
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
# EnableServiceHealthFilter = false
|
||||
|
||||
# Endpoint to use when connecting to Rancher
|
||||
#
|
||||
# Required
|
||||
|
|
Loading…
Reference in a new issue