Merge pull request #1208 from containous/merge-v1.2.0-rc2-master
Merge v1.2.0 rc2 master
This commit is contained in:
commit
7d83027954
23 changed files with 752 additions and 68 deletions
|
@ -9,7 +9,7 @@ env:
|
|||
- secure: btt4r13t09gQlHb6gYrvGC2yGCMMHfnp1Mz1RQedc4Mpf/FfT8aE6xmK2a2i9CCvskjrP0t/BFaS4yxIURjnFRn+ugQIEa0pLspB9UJArW/vgOSpIWM9/OQ/fg8z5XuMxN6Md4DL1/iLypMNSageA1x0TRdt89+D1N1dALpg5XRCXLFbC84TLi0gjlFuib9ibPKzEhLT+anCRJ6iZMzeupDSoaCVbAtJMoDvXw4+4AcRZ1+k4MybBLyCib5boaEOt4pTT88mz4Kk0YaMwPVJyg9Qv36VqyUcPS09Yd95LuyVQ4+tZt8Y1ccbIzULsK+sLM3hLCzxlmlpN3dQBlZJiiRtQde0mgGAKyC0P0A1XjuDTywcsa5edB+fTk1Dsewz9xZ9V0NmMz8t+UNZnaSsAPga9i86jULbXUUwMVSzVRc+Xgx02liB/8qI1xYC9FM6ilStt7rn7mF0k3KbiWhcptgeXjO6Lah9FjEKd5w4MXsdUSTi/86rQaLo+kj+XdaTrXCTulKHyRyQEUj+8V1w0oVz7pcGjePHd7y5oU9ByifVQy6sytuFBfRZvugM5bKHo+i0pcWvixrZS42DrzwxZJsspANOvqSe5ifVbvOkfUppQdCBIwptxV5N1b49XPKU3W/w34QJ8xGmKp3TFA7WwVCztriFHjPgiRpB3EG99Bg=
|
||||
- REPO: $TRAVIS_REPO_SLUG
|
||||
- VERSION: $TRAVIS_TAG
|
||||
- CODENAME: camembert
|
||||
- CODENAME: morbier
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
|
146
CHANGELOG.md
146
CHANGELOG.md
|
@ -1,5 +1,151 @@
|
|||
# Change Log
|
||||
|
||||
|
||||
## [v1.2.0-rc2](https://github.com/containous/traefik/tree/v1.2.0-rc2) (2017-03-01)
|
||||
[Full Changelog](https://github.com/containous/traefik/compare/v1.2.0-rc1...v1.2.0-rc2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Are there plans to support the service type ExternalName in Kubernetes? [\#1142](https://github.com/containous/traefik/issues/1142)
|
||||
- Kubernetes Ingress and sticky support [\#911](https://github.com/containous/traefik/issues/911)
|
||||
- kubernetes client does not support InsecureSkipVerify [\#876](https://github.com/containous/traefik/issues/876)
|
||||
- Support active health checking like HAProxy [\#824](https://github.com/containous/traefik/issues/824)
|
||||
- Allow k8s ingress controller serviceAccountToken and serviceAccountCACert to be changed [\#611](https://github.com/containous/traefik/issues/611)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[rancher\] invalid memory address or nil pointer dereference [\#1134](https://github.com/containous/traefik/issues/1134)
|
||||
- Kubernetes default backend should work [\#1073](https://github.com/containous/traefik/issues/1073)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Are release Download links broken? [\#1201](https://github.com/containous/traefik/issues/1201)
|
||||
- Bind to specific ip address [\#1193](https://github.com/containous/traefik/issues/1193)
|
||||
- DNS01 challenge use the wrong zone through route53 [\#1192](https://github.com/containous/traefik/issues/1192)
|
||||
- Reverse proxy https to http backends fails [\#1180](https://github.com/containous/traefik/issues/1180)
|
||||
- Swarm Mode + Letsecrypt + KV Store [\#1176](https://github.com/containous/traefik/issues/1176)
|
||||
- docker deploy -c example.yml e [\#1169](https://github.com/containous/traefik/issues/1169)
|
||||
- Traefik not finding dynamically added services \(Docker Swarm Mode\) [\#1168](https://github.com/containous/traefik/issues/1168)
|
||||
- Traefik with Kubernetes backend - keep getting 401 on all GET requests to kube-apiserver [\#1166](https://github.com/containous/traefik/issues/1166)
|
||||
- Near line 15 \(last key parsed 'backends.backend-monitor-viz.servers'\): Key 'backends.backend-monitor-viz.servers.server-monitor\_viz-1' has already been defined. [\#1154](https://github.com/containous/traefik/issues/1154)
|
||||
- How to reuse SSL certificates automatically fetched from Let´s encrypt? [\#1152](https://github.com/containous/traefik/issues/1152)
|
||||
- Dynamically ban ip when backend repeatedly returns specified status code. \( 403 \) [\#1136](https://github.com/containous/traefik/issues/1136)
|
||||
- Always get 404 accessing my nginx backend service [\#1112](https://github.com/containous/traefik/issues/1112)
|
||||
- Incomplete Docu [\#1091](https://github.com/containous/traefik/issues/1091)
|
||||
- LoadCertificateForDomains: runtime error: invalid memory address [\#1069](https://github.com/containous/traefik/issues/1069)
|
||||
- Traefik creating backends & mappings for ingress annotated with ingress.class: nginx [\#1058](https://github.com/containous/traefik/issues/1058)
|
||||
- ACME file format description [\#1012](https://github.com/containous/traefik/issues/1012)
|
||||
- SwarmMode - Not routing on worker node [\#838](https://github.com/containous/traefik/issues/838)
|
||||
- Migrate k8s to kubernetes/client-go [\#678](https://github.com/containous/traefik/issues/678)
|
||||
- Support for sticky session with kubernetes ingress as backend [\#674](https://github.com/containous/traefik/issues/674)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Revert "Ensure that we don't add balancees with no health check runs … [\#1198](https://github.com/containous/traefik/pull/1198) ([jangie](https://github.com/jangie))
|
||||
- Small fixes and improvments [\#1173](https://github.com/containous/traefik/pull/1173) ([SantoDE](https://github.com/SantoDE))
|
||||
- Fix docker issues with global and dead tasks [\#1167](https://github.com/containous/traefik/pull/1167) ([christopherobin](https://github.com/christopherobin))
|
||||
- Better ECS error checking [\#1143](https://github.com/containous/traefik/pull/1143) ([lpetre](https://github.com/lpetre))
|
||||
- Fix stats race condition [\#1141](https://github.com/containous/traefik/pull/1141) ([emilevauge](https://github.com/emilevauge))
|
||||
- ECS: Docs - info about cred. resolution and required access policies [\#1137](https://github.com/containous/traefik/pull/1137) ([rickard-von-essen](https://github.com/rickard-von-essen))
|
||||
- Healthcheck tests and doc [\#1132](https://github.com/containous/traefik/pull/1132) ([Juliens](https://github.com/Juliens))
|
||||
|
||||
## [v1.2.0-rc1](https://github.com/containous/traefik/tree/v1.2.0-rc1) (2017-02-06)
|
||||
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.2...v1.2.0-rc1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add FreeBSD and OpenBSD to release builds [\#923](https://github.com/containous/traefik/issues/923)
|
||||
- Write authenticated user to header key [\#802](https://github.com/containous/traefik/issues/802)
|
||||
- Question: Wildcard Host for Kubernetes Ingress [\#792](https://github.com/containous/traefik/issues/792)
|
||||
- First commit prometheus middleware. [\#1022](https://github.com/containous/traefik/pull/1022) ([enxebre](https://github.com/enxebre))
|
||||
- Use deployment primitives from travis [\#843](https://github.com/containous/traefik/pull/843) ([guilhem](https://github.com/guilhem))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Increase Docker API version to work with Windows Containers [\#1094](https://github.com/containous/traefik/issues/1094)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- How could I know whether forwarding path is correctly set? [\#1111](https://github.com/containous/traefik/issues/1111)
|
||||
- ACME + Docker-compose labels [\#1099](https://github.com/containous/traefik/issues/1099)
|
||||
- Loadbalance between 2 containers in Docker Swarm Mode [\#1095](https://github.com/containous/traefik/issues/1095)
|
||||
- Add DNS01 letsencrypt challenge support through AWS. [\#1093](https://github.com/containous/traefik/issues/1093)
|
||||
- New Release Cut [\#1092](https://github.com/containous/traefik/issues/1092)
|
||||
- Marathon integration changed default backend server port from task-level to application-level [\#1072](https://github.com/containous/traefik/issues/1072)
|
||||
- websockets not working when compress = true in toml config. [\#1059](https://github.com/containous/traefik/issues/1059)
|
||||
- Proxying 403 http status into the application [\#1044](https://github.com/containous/traefik/issues/1044)
|
||||
- Normalize auto generated frontend-rule \(docker\) [\#1043](https://github.com/containous/traefik/issues/1043)
|
||||
- Traefik with Consul catalog backend + Registrator [\#1039](https://github.com/containous/traefik/issues/1039)
|
||||
- \[Configuration help\] Can't connect to docker containers under a domain path [\#1032](https://github.com/containous/traefik/issues/1032)
|
||||
- Kubernetes and etcd backend : `storeconfig` fails. [\#1031](https://github.com/containous/traefik/issues/1031)
|
||||
- kubernetes: Undefined backend 'X/' for frontend X/" [\#1026](https://github.com/containous/traefik/issues/1026)
|
||||
- TLS handshake error [\#1025](https://github.com/containous/traefik/issues/1025)
|
||||
- Traefik failing on POST request [\#1008](https://github.com/containous/traefik/issues/1008)
|
||||
- how config traffic.toml http 80 without basic auth, traefik WebUI 8080 with basic auth [\#1001](https://github.com/containous/traefik/issues/1001)
|
||||
- Docs 404 [\#995](https://github.com/containous/traefik/issues/995)
|
||||
- Disable acme for non https endpoints [\#989](https://github.com/containous/traefik/issues/989)
|
||||
- Add parameter to configure TLS entrypoints with ca-bundle file [\#984](https://github.com/containous/traefik/issues/984)
|
||||
- docker multiple networks routing [\#970](https://github.com/containous/traefik/issues/970)
|
||||
- don't add Docker containers not on the same network as traefik [\#959](https://github.com/containous/traefik/issues/959)
|
||||
- Multiple frontend routes [\#957](https://github.com/containous/traefik/issues/957)
|
||||
- SNI based routing without TLS offloading [\#933](https://github.com/containous/traefik/issues/933)
|
||||
- NEO4J + traefik proxy Issues [\#907](https://github.com/containous/traefik/issues/907)
|
||||
- ACME OnDemand ignores entrypoint certificate [\#672](https://github.com/containous/traefik/issues/672)
|
||||
- Ability to use self-signed certificates for local development [\#399](https://github.com/containous/traefik/issues/399)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix checkout initial before calling rmpr [\#1124](https://github.com/containous/traefik/pull/1124) ([emilevauge](https://github.com/emilevauge))
|
||||
- Feature rancher integration [\#1120](https://github.com/containous/traefik/pull/1120) ([SantoDE](https://github.com/SantoDE))
|
||||
- Fix glide go units [\#1119](https://github.com/containous/traefik/pull/1119) ([emilevauge](https://github.com/emilevauge))
|
||||
- Carry \#818 — Add systemd watchdog feature [\#1116](https://github.com/containous/traefik/pull/1116) ([vdemeester](https://github.com/vdemeester))
|
||||
- Skip file permission check on Windows [\#1115](https://github.com/containous/traefik/pull/1115) ([StefanScherer](https://github.com/StefanScherer))
|
||||
- Fix Docker API version for Windows [\#1113](https://github.com/containous/traefik/pull/1113) ([StefanScherer](https://github.com/StefanScherer))
|
||||
- Fix git rpr [\#1109](https://github.com/containous/traefik/pull/1109) ([emilevauge](https://github.com/emilevauge))
|
||||
- Fix docker version specifier [\#1108](https://github.com/containous/traefik/pull/1108) ([timoreimann](https://github.com/timoreimann))
|
||||
- Merge v1.1.2 master [\#1105](https://github.com/containous/traefik/pull/1105) ([emilevauge](https://github.com/emilevauge))
|
||||
- add sh before script in deploy... [\#1103](https://github.com/containous/traefik/pull/1103) ([emilevauge](https://github.com/emilevauge))
|
||||
- \[doc\] typo fixes for kubernetes user guide [\#1102](https://github.com/containous/traefik/pull/1102) ([bamarni](https://github.com/bamarni))
|
||||
- add skip\_cleanup in deploy [\#1101](https://github.com/containous/traefik/pull/1101) ([emilevauge](https://github.com/emilevauge))
|
||||
- Fix k8s example UI port. [\#1098](https://github.com/containous/traefik/pull/1098) ([ddunkin](https://github.com/ddunkin))
|
||||
- Fix marathon provider [\#1090](https://github.com/containous/traefik/pull/1090) ([diegooliveira](https://github.com/diegooliveira))
|
||||
- Add an ECS provider [\#1088](https://github.com/containous/traefik/pull/1088) ([lpetre](https://github.com/lpetre))
|
||||
- Update comment to reflect the code [\#1087](https://github.com/containous/traefik/pull/1087) ([np](https://github.com/np))
|
||||
- update NYTimes/gziphandler fixes \#1059 [\#1084](https://github.com/containous/traefik/pull/1084) ([JamesKyburz](https://github.com/JamesKyburz))
|
||||
- Ensure that we don't add balancees with no health check runs if there is a health check defined on it [\#1080](https://github.com/containous/traefik/pull/1080) ([jangie](https://github.com/jangie))
|
||||
- Add FreeBSD & OpenBSD to crossbinary [\#1078](https://github.com/containous/traefik/pull/1078) ([geoffgarside](https://github.com/geoffgarside))
|
||||
- Fix metrics for multiple entry points [\#1071](https://github.com/containous/traefik/pull/1071) ([matevzmihalic](https://github.com/matevzmihalic))
|
||||
- Allow setting load balancer method and sticky using service annotations [\#1068](https://github.com/containous/traefik/pull/1068) ([bakins](https://github.com/bakins))
|
||||
- Fix travis script [\#1067](https://github.com/containous/traefik/pull/1067) ([emilevauge](https://github.com/emilevauge))
|
||||
- Add missing fmt verb specifier in k8s provider. [\#1066](https://github.com/containous/traefik/pull/1066) ([timoreimann](https://github.com/timoreimann))
|
||||
- Add git rpr command [\#1063](https://github.com/containous/traefik/pull/1063) ([emilevauge](https://github.com/emilevauge))
|
||||
- Fix k8s example [\#1062](https://github.com/containous/traefik/pull/1062) ([emilevauge](https://github.com/emilevauge))
|
||||
- Replace underscores to dash in autogenerated urls \(docker provider\) [\#1061](https://github.com/containous/traefik/pull/1061) ([WTFKr0](https://github.com/WTFKr0))
|
||||
- Don't run go test on .glide cache folder [\#1057](https://github.com/containous/traefik/pull/1057) ([vdemeester](https://github.com/vdemeester))
|
||||
- Allow setting circuitbreaker expression via Kubernetes annotation [\#1056](https://github.com/containous/traefik/pull/1056) ([bakins](https://github.com/bakins))
|
||||
- Improving instrumentation. [\#1042](https://github.com/containous/traefik/pull/1042) ([enxebre](https://github.com/enxebre))
|
||||
- Update user guide for upcoming `docker stack deploy` [\#1041](https://github.com/containous/traefik/pull/1041) ([twelvelabs](https://github.com/twelvelabs))
|
||||
- Support sticky sessions under SWARM Mode. \#1024 [\#1033](https://github.com/containous/traefik/pull/1033) ([foleymic](https://github.com/foleymic))
|
||||
- Allow for wildcards in k8s ingress host, fixes \#792 [\#1029](https://github.com/containous/traefik/pull/1029) ([sheerun](https://github.com/sheerun))
|
||||
- Don't fetch ACME certificates for frontends using non-TLS entrypoints \(\#989\) [\#1023](https://github.com/containous/traefik/pull/1023) ([syfonseq](https://github.com/syfonseq))
|
||||
- Return Proper Non-ACME certificate - Fixes Issue 672 [\#1018](https://github.com/containous/traefik/pull/1018) ([dtomcej](https://github.com/dtomcej))
|
||||
- Fix docs build and add missing benchmarks page [\#1017](https://github.com/containous/traefik/pull/1017) ([csabapalfi](https://github.com/csabapalfi))
|
||||
- Set a NopCloser request body with retry middleware [\#1016](https://github.com/containous/traefik/pull/1016) ([bamarni](https://github.com/bamarni))
|
||||
- instruct to flatten dependencies with glide [\#1010](https://github.com/containous/traefik/pull/1010) ([bamarni](https://github.com/bamarni))
|
||||
- check permissions on acme.json during startup [\#1009](https://github.com/containous/traefik/pull/1009) ([bamarni](https://github.com/bamarni))
|
||||
- \[doc\] few tweaks on the basics page [\#1005](https://github.com/containous/traefik/pull/1005) ([bamarni](https://github.com/bamarni))
|
||||
- Import order as goimports does [\#1004](https://github.com/containous/traefik/pull/1004) ([vdemeester](https://github.com/vdemeester))
|
||||
- See the right go report badge [\#991](https://github.com/containous/traefik/pull/991) ([guilhem](https://github.com/guilhem))
|
||||
- Add multiple values for one rule to docs [\#978](https://github.com/containous/traefik/pull/978) ([j0hnsmith](https://github.com/j0hnsmith))
|
||||
- Add ACME/Let’s Encrypt integration tests [\#975](https://github.com/containous/traefik/pull/975) ([trecloux](https://github.com/trecloux))
|
||||
- deploy.sh: upload release source tarball [\#969](https://github.com/containous/traefik/pull/969) ([Mic92](https://github.com/Mic92))
|
||||
- toml zookeeper doc fix [\#948](https://github.com/containous/traefik/pull/948) ([brdude](https://github.com/brdude))
|
||||
- Add Rule AddPrefix [\#931](https://github.com/containous/traefik/pull/931) ([Juliens](https://github.com/Juliens))
|
||||
- Add bug command [\#921](https://github.com/containous/traefik/pull/921) ([emilevauge](https://github.com/emilevauge))
|
||||
- \(WIP\) feat: HealthCheck [\#918](https://github.com/containous/traefik/pull/918) ([Juliens](https://github.com/Juliens))
|
||||
- Add ability to set authenticated user in request header [\#889](https://github.com/containous/traefik/pull/889) ([ViViDboarder](https://github.com/ViViDboarder))
|
||||
- IP-per-task: [\#841](https://github.com/containous/traefik/pull/841) ([diegooliveira](https://github.com/diegooliveira))
|
||||
|
||||
## [v1.1.2](https://github.com/containous/traefik/tree/v1.1.2) (2016-12-15)
|
||||
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.1...v1.1.2)
|
||||
|
||||
|
|
|
@ -239,6 +239,20 @@ For example:
|
|||
[backends.backend1.loadbalancer]
|
||||
sticky = true
|
||||
```
|
||||
|
||||
Healthcheck URL can be configured with a relative URL for `healthcheck.URL`.
|
||||
Interval between healthcheck can be configured by using `healthcheck.interval`
|
||||
(default: 30s)
|
||||
|
||||
For example:
|
||||
```toml
|
||||
[backends]
|
||||
[backends.backend1]
|
||||
[backends.backend1.healthcheck]
|
||||
URL = "/health"
|
||||
interval = "10s"
|
||||
```
|
||||
|
||||
## Servers
|
||||
|
||||
Servers are simply defined using a `URL`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
|
||||
|
|
99
docs/toml.md
99
docs/toml.md
|
@ -1423,3 +1423,102 @@ Labels can be used on task containers to override default behaviour:
|
|||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||
- `traefik.frontend.priority=10`: override default frontend priority
|
||||
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||
|
||||
If `AccessKeyID`/`SecretAccessKey` is not given credentials will be resolved in the following order:
|
||||
|
||||
- From environment variables; `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.
|
||||
- Shared credentials, determined by `AWS_PROFILE` and `AWS_SHARED_CREDENTIALS_FILE`, defaults to `default` and `~/.aws/credentials`.
|
||||
- EC2 instance role or ECS task role
|
||||
|
||||
Træfɪk needs the following policy to read ECS information:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Traefik ECS read access",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecs:ListTasks",
|
||||
"ecs:DescribeTasks",
|
||||
"ecs:DescribeContainerInstances",
|
||||
"ecs:DescribeTaskDefinition",
|
||||
"ec2:DescribeInstances"
|
||||
],
|
||||
"Resource": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# Rancher backend
|
||||
|
||||
Træfɪk can be configured to use Rancher as a backend configuration:
|
||||
|
||||
|
||||
```toml
|
||||
################################################################
|
||||
# Rancher configuration backend
|
||||
################################################################
|
||||
|
||||
# Enable Rancher configuration backend
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
[rancher]
|
||||
|
||||
# Default domain used.
|
||||
# Can be overridden by setting the "traefik.domain" label on an service.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
domain = "rancher.localhost"
|
||||
|
||||
# Enable watch Rancher changes
|
||||
#
|
||||
# Optional
|
||||
# Default: true
|
||||
#
|
||||
Watch = true
|
||||
|
||||
# Expose Rancher services by default in traefik
|
||||
#
|
||||
# Optional
|
||||
# Default: true
|
||||
#
|
||||
ExposedByDefault = false
|
||||
|
||||
# Endpoint to use when connecting to Rancher
|
||||
#
|
||||
# Optional
|
||||
# Endpoint = "http://rancherserver.example.com"
|
||||
|
||||
# AccessKey to use when connecting to Rancher
|
||||
#
|
||||
# Optional
|
||||
# AccessKey = "XXXXXXXXX"
|
||||
|
||||
# SecretKey to use when connecting to Rancher
|
||||
#
|
||||
# Optional
|
||||
# SecretKey = "XXXXXXXXXXX"
|
||||
|
||||
```
|
||||
|
||||
If you're deploying traefik as a service within rancher, you can alternatively set these labels on the service to let it only fetch data of its current environment. The settings `endpoint`, `accesskey` and `secretkey` can be omitted then.
|
||||
|
||||
- `io.rancher.container.create_agent=true`
|
||||
- `io.rancher.container.agent.role=environment`
|
||||
|
||||
Labels can be used on task containers to override default behaviour:
|
||||
|
||||
- `traefik.protocol=https`: override the default `http` protocol
|
||||
- `traefik.weight=10`: assign this weight to the container
|
||||
- `traefik.enable=false`: disable this container in Træfɪk
|
||||
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
|
||||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||
- `traefik.frontend.priority=10`: override default frontend priority
|
||||
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||
|
|
10
examples/compose-rancher.yml
Normal file
10
examples/compose-rancher.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
traefik:
|
||||
image: traefik
|
||||
command: --web --rancher --rancher.domain=rancher.localhost --logLevel=DEBUG
|
||||
labels:
|
||||
io.rancher.container.agent.role: environment
|
||||
io.rancher.container.create_agent: 'true'
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
6
glide.lock
generated
6
glide.lock
generated
|
@ -1,5 +1,5 @@
|
|||
hash: b2ac93355c3f551a75216a800337cee9321f6c9a04a18ab1fa8d8152e89b7595
|
||||
updated: 2017-02-20T16:04:18.834166585+01:00
|
||||
hash: f2a0b9af55c8312762e4148bd876e5bd2451c240b407fbb6d4a5dbc56bf46c05
|
||||
updated: 2017-03-03T10:21:14.720631882+01:00
|
||||
imports:
|
||||
- name: bitbucket.org/ww/goautoneg
|
||||
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
|
||||
|
@ -444,7 +444,7 @@ imports:
|
|||
- assert
|
||||
- mock
|
||||
- name: github.com/thoas/stats
|
||||
version: 79b768ff1780f4e5b0ed132e192bfeefe9f85a9c
|
||||
version: 152b5d051953fdb6e45f14b6826962aadc032324
|
||||
- name: github.com/timewasted/linode
|
||||
version: 37e84520dcf74488f67654f9c775b9752c232dc1
|
||||
subpackages:
|
||||
|
|
|
@ -53,6 +53,7 @@ import:
|
|||
subpackages:
|
||||
- mock
|
||||
- package: github.com/thoas/stats
|
||||
version: 152b5d051953fdb6e45f14b6826962aadc032324
|
||||
- package: github.com/unrolled/render
|
||||
- package: github.com/vdemeester/docker-events
|
||||
version: be74d4929ec1ad118df54349fda4b0cba60f849b
|
||||
|
|
|
@ -26,6 +26,7 @@ func GetHealthCheck() *HealthCheck {
|
|||
// BackendHealthCheck HealthCheck configuration for a backend
|
||||
type BackendHealthCheck struct {
|
||||
URL string
|
||||
Interval time.Duration
|
||||
DisabledURLs []*url.URL
|
||||
lb loadBalancer
|
||||
}
|
||||
|
@ -49,8 +50,8 @@ func newHealthCheck() *HealthCheck {
|
|||
}
|
||||
|
||||
// NewBackendHealthCheck Instantiate a new BackendHealthCheck
|
||||
func NewBackendHealthCheck(URL string, lb loadBalancer) *BackendHealthCheck {
|
||||
return &BackendHealthCheck{URL, nil, lb}
|
||||
func NewBackendHealthCheck(URL string, interval time.Duration, lb loadBalancer) *BackendHealthCheck {
|
||||
return &BackendHealthCheck{URL, interval, nil, lb}
|
||||
}
|
||||
|
||||
//SetBackendsConfiguration set backends configuration
|
||||
|
@ -70,7 +71,7 @@ func (hc *HealthCheck) execute(ctx context.Context) {
|
|||
currentBackendID := backendID
|
||||
safe.Go(func() {
|
||||
for {
|
||||
ticker := time.NewTicker(time.Second * 30)
|
||||
ticker := time.NewTicker(currentBackend.Interval)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Debugf("Stopping all current Healthcheck goroutines")
|
||||
|
|
27
integration/fixtures/healthcheck/simple.toml
Normal file
27
integration/fixtures/healthcheck/simple.toml
Normal file
|
@ -0,0 +1,27 @@
|
|||
defaultEntryPoints = ["http"]
|
||||
|
||||
logLevel = "DEBUG"
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
|
||||
[file]
|
||||
[backends]
|
||||
[backends.backend1]
|
||||
[backends.backend1.healthcheck]
|
||||
url = "/health"
|
||||
interval = "1s"
|
||||
[backends.backend1.servers.server1]
|
||||
url = "http://{{.Server1}}:80"
|
||||
[backends.backend1.servers.server2]
|
||||
url = "http://{{.Server2}}:80"
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
backend = "backend1"
|
||||
[frontends.frontend1.routes.test_1]
|
||||
rule = "Host:test.localhost"
|
91
integration/healthcheck_test.go
Normal file
91
integration/healthcheck_test.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/integration/utils"
|
||||
"github.com/go-check/check"
|
||||
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// HealchCheck test suites (using libcompose)
|
||||
type HealchCheckSuite struct{ BaseSuite }
|
||||
|
||||
func (s *HealchCheckSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "healthcheck")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
}
|
||||
|
||||
func (s *HealchCheckSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
||||
whoami1Host := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
whoami2Host := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
|
||||
file := s.adaptFile(c, "fixtures/healthcheck/simple.toml", struct {
|
||||
Server1 string
|
||||
Server2 string
|
||||
}{whoami1Host, whoami2Host})
|
||||
defer os.Remove(file)
|
||||
cmd := exec.Command(traefikBinary, "--configFile="+file)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// wait for traefik
|
||||
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.Contains(string(body), "Host:test.localhost") {
|
||||
return errors.New("Incorrect traefik config: " + string(body))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/health", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = "test.localhost"
|
||||
|
||||
resp, err := client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||
|
||||
healthReq, err := http.NewRequest("POST", "http://"+whoami1Host+"/health", bytes.NewBuffer([]byte("500")))
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = client.Do(healthReq)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
time.Sleep(time.Second * 3)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||
|
||||
// TODO validate : run on 80
|
||||
resp, err = http.Get("http://127.0.0.1:8000/")
|
||||
|
||||
// Expected a 404 as we did not configure anything
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, 404)
|
||||
}
|
5
integration/resources/compose/healthcheck.yml
Normal file
5
integration/resources/compose/healthcheck.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
whoami1:
|
||||
image: emilevauge/whoami
|
||||
|
||||
whoami2:
|
||||
image: emilevauge/whoami
|
|
@ -626,11 +626,12 @@ func (provider *Docker) listServices(ctx context.Context, dockerClient client.AP
|
|||
for _, service := range serviceList {
|
||||
dockerData := parseService(service, networkMap)
|
||||
useSwarmLB, _ := strconv.ParseBool(provider.getIsBackendLBSwarm(dockerData))
|
||||
isGlobalSvc := service.Spec.Mode.Global != nil
|
||||
|
||||
if useSwarmLB {
|
||||
dockerDataList = append(dockerDataList, dockerData)
|
||||
} else {
|
||||
dockerDataListTasks, err = listTasks(ctx, dockerClient, service.ID, dockerData, networkMap)
|
||||
dockerDataListTasks, err = listTasks(ctx, dockerClient, service.ID, dockerData, networkMap, isGlobalSvc)
|
||||
|
||||
for _, dockerDataTask := range dockerDataListTasks {
|
||||
dockerDataList = append(dockerDataList, dockerDataTask)
|
||||
|
@ -675,9 +676,10 @@ func parseService(service swarmtypes.Service, networkMap map[string]*dockertypes
|
|||
}
|
||||
|
||||
func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID string,
|
||||
serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource) ([]dockerData, error) {
|
||||
serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource, isGlobalSvc bool) ([]dockerData, error) {
|
||||
serviceIDFilter := filters.NewArgs()
|
||||
serviceIDFilter.Add("service", serviceID)
|
||||
serviceIDFilter.Add("desired-state", "running")
|
||||
taskList, err := dockerClient.TaskList(ctx, dockertypes.TaskListOptions{Filter: serviceIDFilter})
|
||||
|
||||
if err != nil {
|
||||
|
@ -686,13 +688,13 @@ func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID str
|
|||
var dockerDataList []dockerData
|
||||
|
||||
for _, task := range taskList {
|
||||
dockerData := parseTasks(task, serviceDockerData, networkMap)
|
||||
dockerData := parseTasks(task, serviceDockerData, networkMap, isGlobalSvc)
|
||||
dockerDataList = append(dockerDataList, dockerData)
|
||||
}
|
||||
return dockerDataList, err
|
||||
}
|
||||
|
||||
func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource) dockerData {
|
||||
func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource, isGlobalSvc bool) dockerData {
|
||||
dockerData := dockerData{
|
||||
ServiceName: serviceDockerData.Name,
|
||||
Name: serviceDockerData.Name + "." + strconv.Itoa(task.Slot),
|
||||
|
@ -700,6 +702,10 @@ func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap m
|
|||
NetworkSettings: networkSettings{},
|
||||
}
|
||||
|
||||
if isGlobalSvc == true {
|
||||
dockerData.Name = serviceDockerData.Name + "." + task.ID
|
||||
}
|
||||
|
||||
if task.NetworksAttachments != nil {
|
||||
dockerData.NetworkSettings.Networks = make(map[string]*networkData)
|
||||
for _, virtualIP := range task.NetworksAttachments {
|
||||
|
|
|
@ -2184,3 +2184,90 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwarmTaskParsing(t *testing.T) {
|
||||
cases := []struct {
|
||||
service swarm.Service
|
||||
tasks []swarm.Task
|
||||
isGlobalSvc bool
|
||||
expectedNames map[string]string
|
||||
networks map[string]*docker.NetworkResource
|
||||
}{
|
||||
{
|
||||
service: swarm.Service{
|
||||
Spec: swarm.ServiceSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: "container",
|
||||
},
|
||||
},
|
||||
},
|
||||
tasks: []swarm.Task{
|
||||
{
|
||||
ID: "id1",
|
||||
Slot: 1,
|
||||
},
|
||||
{
|
||||
ID: "id2",
|
||||
Slot: 2,
|
||||
},
|
||||
{
|
||||
ID: "id3",
|
||||
Slot: 3,
|
||||
},
|
||||
},
|
||||
isGlobalSvc: false,
|
||||
expectedNames: map[string]string{
|
||||
"id1": "container.1",
|
||||
"id2": "container.2",
|
||||
"id3": "container.3",
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
service: swarm.Service{
|
||||
Spec: swarm.ServiceSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: "container",
|
||||
},
|
||||
},
|
||||
},
|
||||
tasks: []swarm.Task{
|
||||
{
|
||||
ID: "id1",
|
||||
},
|
||||
{
|
||||
ID: "id2",
|
||||
},
|
||||
{
|
||||
ID: "id3",
|
||||
},
|
||||
},
|
||||
isGlobalSvc: true,
|
||||
expectedNames: map[string]string{
|
||||
"id1": "container.id1",
|
||||
"id2": "container.id2",
|
||||
"id3": "container.id3",
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range cases {
|
||||
dockerData := parseService(e.service, e.networks)
|
||||
|
||||
for _, task := range e.tasks {
|
||||
taskDockerData := parseTasks(task, dockerData, map[string]*docker.NetworkResource{}, e.isGlobalSvc)
|
||||
if !reflect.DeepEqual(taskDockerData.Name, e.expectedNames[task.ID]) {
|
||||
t.Fatalf("expect %v, got %v", e.expectedNames[task.ID], taskDockerData.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,37 +275,48 @@ func (provider *ECS) listInstances(ctx context.Context, client *awsClient) ([]ec
|
|||
}
|
||||
|
||||
func (provider *ECS) lookupEc2Instances(ctx context.Context, client *awsClient, containerArns []*string) ([]*ec2.Instance, error) {
|
||||
req, containerResp := client.ecs.DescribeContainerInstancesRequest(&ecs.DescribeContainerInstancesInput{
|
||||
ContainerInstances: containerArns,
|
||||
Cluster: &provider.Cluster,
|
||||
})
|
||||
|
||||
if err := wrapAws(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
order := make(map[string]int)
|
||||
instanceIds := make([]*string, len(containerArns))
|
||||
instances := make([]*ec2.Instance, len(containerArns))
|
||||
for i, arn := range containerArns {
|
||||
order[*arn] = i
|
||||
}
|
||||
|
||||
instanceIds := make([]*string, len(containerArns))
|
||||
for i, container := range containerResp.ContainerInstances {
|
||||
order[*container.Ec2InstanceId] = order[*container.ContainerInstanceArn]
|
||||
instanceIds[i] = container.Ec2InstanceId
|
||||
req, _ := client.ecs.DescribeContainerInstancesRequest(&ecs.DescribeContainerInstancesInput{
|
||||
ContainerInstances: containerArns,
|
||||
Cluster: &provider.Cluster,
|
||||
})
|
||||
|
||||
for ; req != nil; req = req.NextPage() {
|
||||
if err := wrapAws(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
containerResp := req.Data.(*ecs.DescribeContainerInstancesOutput)
|
||||
for i, container := range containerResp.ContainerInstances {
|
||||
order[*container.Ec2InstanceId] = order[*container.ContainerInstanceArn]
|
||||
instanceIds[i] = container.Ec2InstanceId
|
||||
}
|
||||
}
|
||||
|
||||
req, instancesResp := client.ec2.DescribeInstancesRequest(&ec2.DescribeInstancesInput{
|
||||
req, _ = client.ec2.DescribeInstancesRequest(&ec2.DescribeInstancesInput{
|
||||
InstanceIds: instanceIds,
|
||||
})
|
||||
|
||||
if err := wrapAws(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for ; req != nil; req = req.NextPage() {
|
||||
if err := wrapAws(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instances := make([]*ec2.Instance, len(containerArns))
|
||||
for _, r := range instancesResp.Reservations {
|
||||
instances[order[*r.Instances[0].InstanceId]] = r.Instances[0]
|
||||
instancesResp := req.Data.(*ec2.DescribeInstancesOutput)
|
||||
for _, r := range instancesResp.Reservations {
|
||||
for _, i := range r.Instances {
|
||||
if i.InstanceId != nil {
|
||||
instances[order[*i.InstanceId]] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return instances, nil
|
||||
}
|
||||
|
@ -340,6 +351,23 @@ func (provider *ECS) filterInstance(i ecsInstance) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if i.machine == nil ||
|
||||
i.machine.State == nil ||
|
||||
i.machine.State.Name == nil {
|
||||
log.Debugf("Filtering ecs instance in an missing ec2 information %s (%s)", i.Name, i.ID)
|
||||
return false
|
||||
}
|
||||
|
||||
if *i.machine.State.Name != ec2.InstanceStateNameRunning {
|
||||
log.Debugf("Filtering ecs instance in an incorrect state %s (%s) (state = %s)", i.Name, i.ID, *i.machine.State.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
if i.machine.PrivateIpAddress == nil {
|
||||
log.Debugf("Filtering ecs instance without an ip address %s (%s)", i.Name, i.ID)
|
||||
return false
|
||||
}
|
||||
|
||||
label := i.label("traefik.enable")
|
||||
enabled := provider.ExposedByDefault && label != "false" || label == "true"
|
||||
if !enabled {
|
||||
|
|
|
@ -37,6 +37,9 @@ func makeEcsInstance(containerDef *ecs.ContainerDefinition) ecsInstance {
|
|||
containerDefinition: containerDef,
|
||||
machine: &ec2.Instance{
|
||||
PrivateIpAddress: aws.String("10.0.0.0"),
|
||||
State: &ec2.InstanceState{
|
||||
Name: aws.String(ec2.InstanceStateNameRunning),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -70,10 +73,10 @@ func TestEcsProtocol(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.Protocol()
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,10 +92,10 @@ func TestEcsHost(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.Host()
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,10 +111,10 @@ func TestEcsPort(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.Port()
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,10 +136,10 @@ func TestEcsWeight(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.Weight()
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,10 +161,10 @@ func TestEcsPassHostHeader(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.PassHostHeader()
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,10 +186,10 @@ func TestEcsPriority(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.Priority()
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,10 +217,94 @@ func TestEcsEntryPoints(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
for i, c := range cases {
|
||||
value := c.instanceInfo.EntryPoints()
|
||||
if !reflect.DeepEqual(value, c.expected) {
|
||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterInstance(t *testing.T) {
|
||||
|
||||
nilPrivateIP := simpleEcsInstance(map[string]*string{})
|
||||
nilPrivateIP.machine.PrivateIpAddress = nil
|
||||
|
||||
nilMachine := simpleEcsInstance(map[string]*string{})
|
||||
nilMachine.machine = nil
|
||||
|
||||
nilMachineState := simpleEcsInstance(map[string]*string{})
|
||||
nilMachineState.machine.State = nil
|
||||
|
||||
nilMachineStateName := simpleEcsInstance(map[string]*string{})
|
||||
nilMachineStateName.machine.State.Name = nil
|
||||
|
||||
invalidMachineState := simpleEcsInstance(map[string]*string{})
|
||||
invalidMachineState.machine.State.Name = aws.String(ec2.InstanceStateNameStopped)
|
||||
|
||||
cases := []struct {
|
||||
expected bool
|
||||
exposedByDefault bool
|
||||
instanceInfo ecsInstance
|
||||
}{
|
||||
{
|
||||
expected: true,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: false,
|
||||
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: simpleEcsInstance(map[string]*string{
|
||||
"traefik.enable": aws.String("false"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
expected: true,
|
||||
exposedByDefault: false,
|
||||
instanceInfo: simpleEcsInstance(map[string]*string{
|
||||
"traefik.enable": aws.String("true"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: nilPrivateIP,
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: nilMachine,
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: nilMachineState,
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: nilMachineStateName,
|
||||
},
|
||||
{
|
||||
expected: false,
|
||||
exposedByDefault: true,
|
||||
instanceInfo: invalidMachineState,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
provider := &ECS{
|
||||
ExposedByDefault: c.exposedByDefault,
|
||||
}
|
||||
value := provider.filterInstance(c.instanceInfo)
|
||||
if value != c.expected {
|
||||
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,9 +264,6 @@ func (provider *Marathon) taskFilter(task marathon.Task, applications *marathon.
|
|||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Debugf("Filtering marathon task %s with defined healthcheck as no healthcheck has run yet", task.AppID)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -629,7 +629,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
exposedByDefault: true,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -4,6 +4,13 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/ty/fun"
|
||||
"github.com/cenk/backoff"
|
||||
"github.com/containous/traefik/job"
|
||||
|
@ -11,11 +18,6 @@ import (
|
|||
"github.com/containous/traefik/safe"
|
||||
"github.com/containous/traefik/types"
|
||||
rancher "github.com/rancher/go-rancher/client"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -72,7 +74,7 @@ func (provider *Rancher) getFrontendRule(service rancherData) string {
|
|||
if label, err := getServiceLabel(service, "traefik.frontend.rule"); err == nil {
|
||||
return label
|
||||
}
|
||||
return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", "_", -1)) + "." + provider.Domain
|
||||
return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", ".", -1)) + "." + provider.Domain
|
||||
}
|
||||
|
||||
func (provider *Rancher) getFrontendName(service rancherData) string {
|
||||
|
@ -193,13 +195,26 @@ func getServiceLabel(service rancherData, label string) (string, error) {
|
|||
}
|
||||
|
||||
func (provider *Rancher) createClient() (*rancher.RancherClient, error) {
|
||||
|
||||
rancherURL := getenv("CATTLE_URL", provider.Endpoint)
|
||||
accessKey := getenv("CATTLE_ACCESS_KEY", provider.AccessKey)
|
||||
secretKey := getenv("CATTLE_SECRET_KEY", provider.SecretKey)
|
||||
|
||||
return rancher.NewRancherClient(&rancher.ClientOpts{
|
||||
Url: provider.Endpoint,
|
||||
AccessKey: provider.AccessKey,
|
||||
SecretKey: provider.SecretKey,
|
||||
Url: rancherURL,
|
||||
AccessKey: accessKey,
|
||||
SecretKey: secretKey,
|
||||
})
|
||||
}
|
||||
|
||||
func getenv(key, fallback string) string {
|
||||
value := os.Getenv(key)
|
||||
if len(value) == 0 {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
|
@ -207,6 +222,12 @@ func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, p
|
|||
safe.Go(func() {
|
||||
operation := func() error {
|
||||
rancherClient, err := provider.createClient()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create a client for rancher, error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
var environments = listRancherEnvironments(rancherClient)
|
||||
var services = listRancherServices(rancherClient)
|
||||
|
@ -214,11 +235,6 @@ func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, p
|
|||
|
||||
var rancherData = parseRancherData(environments, services, container)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create a client for rancher, error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
configuration := provider.loadRancherConfig(rancherData)
|
||||
configurationChan <- types.ConfigMessage{
|
||||
ProviderName: "rancher",
|
||||
|
|
|
@ -87,6 +87,12 @@ func TestRancherGetFrontendRule(t *testing.T) {
|
|||
},
|
||||
expected: "Host:foo.rancher.localhost",
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Name: "foo/bar",
|
||||
},
|
||||
expected: "Host:foo.bar.rancher.localhost",
|
||||
},
|
||||
{
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
|
@ -388,7 +394,7 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
|||
{
|
||||
services: []rancherData{
|
||||
{
|
||||
Name: "test-service",
|
||||
Name: "test/service",
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "80",
|
||||
},
|
||||
|
@ -405,7 +411,7 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
|||
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test-service-rancher-localhost": {
|
||||
Rule: "Host:test-service.rancher.localhost",
|
||||
Rule: "Host:test.service.rancher.localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ -n "$TRAVIS_TAG" ] && [ "$DOCKER_VERSION" = "1.10.1" ]; then
|
||||
if [ -n "$TRAVIS_TAG" ] && [ "$DOCKER_VERSION" = "1.10.3" ]; then
|
||||
echo "Deploying..."
|
||||
else
|
||||
echo "Skipping deploy"
|
||||
|
|
20
server.go
20
server.go
|
@ -658,7 +658,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
|||
continue frontend
|
||||
}
|
||||
if configuration.Backends[frontend.Backend].HealthCheck != nil {
|
||||
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, rebalancer)
|
||||
var interval time.Duration
|
||||
if configuration.Backends[frontend.Backend].HealthCheck.Interval != "" {
|
||||
interval, err = time.ParseDuration(configuration.Backends[frontend.Backend].HealthCheck.Interval)
|
||||
if err != nil {
|
||||
log.Errorf("Wrong healthcheck interval: %s", err)
|
||||
interval = time.Second * 30
|
||||
}
|
||||
}
|
||||
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rebalancer)
|
||||
}
|
||||
}
|
||||
case types.Wrr:
|
||||
|
@ -684,7 +692,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
|||
}
|
||||
}
|
||||
if configuration.Backends[frontend.Backend].HealthCheck != nil {
|
||||
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, rr)
|
||||
var interval time.Duration
|
||||
if configuration.Backends[frontend.Backend].HealthCheck.Interval != "" {
|
||||
interval, err = time.ParseDuration(configuration.Backends[frontend.Backend].HealthCheck.Interval)
|
||||
if err != nil {
|
||||
log.Errorf("Wrong healthcheck interval: %s", err)
|
||||
interval = time.Second * 30
|
||||
}
|
||||
}
|
||||
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rr)
|
||||
}
|
||||
}
|
||||
maxConns := configuration.Backends[frontend.Backend].MaxConn
|
||||
|
|
|
@ -935,6 +935,52 @@
|
|||
#
|
||||
# filename = "ecs.tmpl"
|
||||
|
||||
################################################################
|
||||
# Rancher configuration backend
|
||||
################################################################
|
||||
|
||||
# Enable Rancher configuration backend
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
[rancher]
|
||||
|
||||
# Default domain used.
|
||||
# Can be overridden by setting the "traefik.domain" label on an service.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
domain = "rancher.localhost"
|
||||
|
||||
# Enable watch Rancher changes
|
||||
#
|
||||
# Optional
|
||||
# Default: true
|
||||
#
|
||||
Watch = true
|
||||
|
||||
# Expose Rancher services by default in traefik
|
||||
#
|
||||
# Optional
|
||||
# Default: true
|
||||
#
|
||||
ExposedByDefault = false
|
||||
|
||||
# Endpoint to use when connecting to Rancher
|
||||
#
|
||||
# Optional
|
||||
# Endpoint = "http://rancherserver.example.com"
|
||||
|
||||
# AccessKey to use when connecting to Rancher
|
||||
#
|
||||
# Optional
|
||||
# AccessKey = "XXXXXXXXX"
|
||||
|
||||
# SecretKey to use when connecting to Rancher
|
||||
#
|
||||
# Optional
|
||||
# SecretKey = "XXXXXXXXXXX"
|
||||
|
||||
|
||||
################################################################
|
||||
# Sample rules
|
||||
|
|
|
@ -39,7 +39,8 @@ type CircuitBreaker struct {
|
|||
|
||||
// HealthCheck holds HealthCheck configuration
|
||||
type HealthCheck struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Interval string `json:"interval,omitempty"`
|
||||
}
|
||||
|
||||
// Server holds server configuration.
|
||||
|
|
Loading…
Reference in a new issue