Merge pull request #938 from containous/merge-v1.1.1-master

Merge v1.1.1 master
This commit is contained in:
Emile Vauge 2016-12-06 09:14:39 +01:00 committed by GitHub
commit d26f06e2d1
41 changed files with 760 additions and 170 deletions

View file

@ -20,6 +20,7 @@ install:
- docker version - docker version
- pip install --user mkdocs - pip install --user mkdocs
- pip install --user pymdown-extensions - pip install --user pymdown-extensions
- pip install --user mkdocs-bootswatch
before_script: before_script:
- make validate - make validate
- make binary - make binary

View file

@ -1,5 +1,312 @@
# Change Log # Change Log
## [v1.1.1](https://github.com/containous/traefik/tree/v1.1.1) (2016-11-29)
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.0...v1.1.1)
**Implemented enhancements:**
- Getting "Kubernetes connection error failed to decode watch event : unexpected EOF" every minute in Traefik log [\#732](https://github.com/containous/traefik/issues/732)
**Fixed bugs:**
- 1.1.0 kubernetes panic: send on closed channel [\#877](https://github.com/containous/traefik/issues/877)
- digest auth example is incorrect [\#869](https://github.com/containous/traefik/issues/869)
- Marathon & Mesos providers' GroupsAsSubDomains option broken [\#867](https://github.com/containous/traefik/issues/867)
- 404 responses when a new Marathon leader is elected [\#653](https://github.com/containous/traefik/issues/653)
**Closed issues:**
- traefik:latest fails to auto-detect Docker containers [\#901](https://github.com/containous/traefik/issues/901)
- Panic error on bare metal Kubernetes \(installed with Kubeadm\) [\#897](https://github.com/containous/traefik/issues/897)
- api backend readOnly: what is the purpose of this setting [\#893](https://github.com/containous/traefik/issues/893)
- file backend: using external file - doesn't work [\#892](https://github.com/containous/traefik/issues/892)
- auth support for web backend [\#891](https://github.com/containous/traefik/issues/891)
- Basic auth with docker labels [\#890](https://github.com/containous/traefik/issues/890)
- file vs inline config [\#888](https://github.com/containous/traefik/issues/888)
- combine Host and HostRegexp rules [\#882](https://github.com/containous/traefik/issues/882)
- \[Question\] Traefik + Kubernetes + Let's Encrypt \(ssl not used\) [\#881](https://github.com/containous/traefik/issues/881)
- Traefik security for dashboard [\#880](https://github.com/containous/traefik/issues/880)
- Kubernetes Nginx Deployment Panic [\#879](https://github.com/containous/traefik/issues/879)
- Kubernetes Example Address already in use [\#872](https://github.com/containous/traefik/issues/872)
- ETCD Backend - frontend/backends missing [\#866](https://github.com/containous/traefik/issues/866)
- \[Swarm mode\] Dashboard does not work on RC4 [\#864](https://github.com/containous/traefik/issues/864)
- Docker v1.1.0 image does not exist [\#861](https://github.com/containous/traefik/issues/861)
- ConsulService catalog do not support multiple rules [\#859](https://github.com/containous/traefik/issues/859)
- Update official docker repo [\#858](https://github.com/containous/traefik/issues/858)
- Still a memory leak with k8s - 1.1 RC4 [\#844](https://github.com/containous/traefik/issues/844)
**Merged pull requests:**
- Fix Swarm panic [\#908](https://github.com/containous/traefik/pull/908) ([emilevauge](https://github.com/emilevauge))
- Fix k8s panic [\#900](https://github.com/containous/traefik/pull/900) ([emilevauge](https://github.com/emilevauge))
- Fix missing value for k8s watch request parameter [\#874](https://github.com/containous/traefik/pull/874) ([codablock](https://github.com/codablock))
- Fix GroupsAsSubDomains option for Mesos and Marathon [\#868](https://github.com/containous/traefik/pull/868) ([ryanleary](https://github.com/ryanleary))
- Normalize backend even if is user-defined [\#865](https://github.com/containous/traefik/pull/865) ([WTFKr0](https://github.com/WTFKr0))
- consul/kv.tmpl: weight default value should be a int [\#826](https://github.com/containous/traefik/pull/826) ([klausenbusk](https://github.com/klausenbusk))
## [v1.1.0](https://github.com/containous/traefik/tree/v1.1.0) (2016-11-17)
[Full Changelog](https://github.com/containous/traefik/compare/v1.0.0...v1.1.0)
**Implemented enhancements:**
- Support healthcheck if present for docker [\#666](https://github.com/containous/traefik/issues/666)
- Standard unit for traefik latency in access log [\#559](https://github.com/containous/traefik/issues/559)
- \[CI\] wiredep marked as unmaintained [\#550](https://github.com/containous/traefik/issues/550)
- Feature Request: Enable Health checks to containers. [\#540](https://github.com/containous/traefik/issues/540)
- Feature Request: SSL Cipher Selection [\#535](https://github.com/containous/traefik/issues/535)
- Error with -consulcatalog and missing load balance method on 1.0.0 [\#524](https://github.com/containous/traefik/issues/524)
- Running Traefik with Docker 1.12 Swarm Mode [\#504](https://github.com/containous/traefik/issues/504)
- Kubernetes provider: should allow the master url to be override [\#501](https://github.com/containous/traefik/issues/501)
- \[FRONTEND\]\[LE\] Pre-generate SSL certificates for "Host:" rules [\#483](https://github.com/containous/traefik/issues/483)
- Frontend Rule evolution [\#437](https://github.com/containous/traefik/issues/437)
- Add a Changelog [\#388](https://github.com/containous/traefik/issues/388)
- Add label matching for kubernetes ingests [\#363](https://github.com/containous/traefik/issues/363)
- Acme in HA Traefik Scenario [\#348](https://github.com/containous/traefik/issues/348)
- HTTP Basic Auth support [\#77](https://github.com/containous/traefik/issues/77)
- Session affinity / stickiness / persistence [\#5](https://github.com/containous/traefik/issues/5)
**Fixed bugs:**
- 1.1.0-rc4 dashboard UX not displaying [\#828](https://github.com/containous/traefik/issues/828)
- Traefik stopped serving on upgrade to v1.1.0-rc3 [\#807](https://github.com/containous/traefik/issues/807)
- cannot access webui/dashboard [\#796](https://github.com/containous/traefik/issues/796)
- Traefik cannot read constraints from KV [\#794](https://github.com/containous/traefik/issues/794)
- HTTP2 - configuration [\#790](https://github.com/containous/traefik/issues/790)
- Cannot provide multiple certificates using flag [\#757](https://github.com/containous/traefik/issues/757)
- Allow multiple certificates on a single entrypoint when trying to use TLS? [\#747](https://github.com/containous/traefik/issues/747)
- traefik \* Users: unsupported type: slice [\#743](https://github.com/containous/traefik/issues/743)
- \[Docker swarm mode\] The traefik.docker.network seems to have no effect [\#719](https://github.com/containous/traefik/issues/719)
- traefik hangs - stops handling requests [\#662](https://github.com/containous/traefik/issues/662)
- Add long jobs in exponential backoff providers [\#626](https://github.com/containous/traefik/issues/626)
- Tip of tree crashes on invalid pointer on Marathon provider [\#624](https://github.com/containous/traefik/issues/624)
- ACME: revoke certificate on agreement update [\#579](https://github.com/containous/traefik/issues/579)
- WebUI: Providers tabs disappeared [\#577](https://github.com/containous/traefik/issues/577)
- traefik version command contains incorrect information when building from master branch [\#569](https://github.com/containous/traefik/issues/569)
- Case sensitive domain names breaks routing [\#562](https://github.com/containous/traefik/issues/562)
- Flag --etcd.endpoint default [\#508](https://github.com/containous/traefik/issues/508)
- Conditional ACME on demand generation [\#505](https://github.com/containous/traefik/issues/505)
- Important delay with streams \(Mozilla EventSource\) [\#503](https://github.com/containous/traefik/issues/503)
- Traefik crashing [\#458](https://github.com/containous/traefik/issues/458)
- traefik.toml constraints error: `Expected map but found 'string'.` [\#451](https://github.com/containous/traefik/issues/451)
- Multiple path separators in the url path causing redirect [\#167](https://github.com/containous/traefik/issues/167)
**Closed issues:**
- All path rules require paths to be lowercase [\#851](https://github.com/containous/traefik/issues/851)
- The UI stops working after a time and have to restart the service. [\#840](https://github.com/containous/traefik/issues/840)
- Incorrect Dashboard page returned [\#831](https://github.com/containous/traefik/issues/831)
- LoadBalancing doesn't work in single node Swarm-mode [\#815](https://github.com/containous/traefik/issues/815)
- cannot connect to docker daemon [\#813](https://github.com/containous/traefik/issues/813)
- Let's encrypt configuration not working [\#805](https://github.com/containous/traefik/issues/805)
- Multiple subdomains for Marathon backend. [\#785](https://github.com/containous/traefik/issues/785)
- traefik-1.1.0-rc1: build error [\#781](https://github.com/containous/traefik/issues/781)
- dependencies installation error [\#755](https://github.com/containous/traefik/issues/755)
- k8s provider w/ acme? [\#752](https://github.com/containous/traefik/issues/752)
- Swarm Docs - How to use a FQDN [\#744](https://github.com/containous/traefik/issues/744)
- Documented ProvidersThrottleDuration value is invalid [\#741](https://github.com/containous/traefik/issues/741)
- Sensible configuration for consulCatalog [\#737](https://github.com/containous/traefik/issues/737)
- Traefik ignoring container listening in more than one TCP port [\#734](https://github.com/containous/traefik/issues/734)
- Loadbalaning issues with traefik and Docker Swarm cluster [\#730](https://github.com/containous/traefik/issues/730)
- issues with marathon app ids containing a dot [\#726](https://github.com/containous/traefik/issues/726)
- Error when using HA acme in kubernetes with etcd [\#725](https://github.com/containous/traefik/issues/725)
- \[Docker swarm mode\] No round robin when using service [\#718](https://github.com/containous/traefik/issues/718)
- Dose it support docker swarm mode [\#712](https://github.com/containous/traefik/issues/712)
- Kubernetes - Undefined backend [\#710](https://github.com/containous/traefik/issues/710)
- How Routing traffic depending on path not domain in docker [\#706](https://github.com/containous/traefik/issues/706)
- Constraints on Consul Catalogue not working as expected [\#703](https://github.com/containous/traefik/issues/703)
- Global InsecureSkipVerify does not work [\#700](https://github.com/containous/traefik/issues/700)
- Traefik crashes when using Consul catalog [\#699](https://github.com/containous/traefik/issues/699)
- \[documentation/feature\] Consul/etcd support atomic multiple key changes now [\#698](https://github.com/containous/traefik/issues/698)
- How to configure which network to use when starting traefik binary? [\#694](https://github.com/containous/traefik/issues/694)
- How to get multiple host headers working for docker labels? [\#692](https://github.com/containous/traefik/issues/692)
- Requests with URL-encoded characters are not forwarded correctly [\#684](https://github.com/containous/traefik/issues/684)
- File Watcher for rules does not work [\#683](https://github.com/containous/traefik/issues/683)
- Issue with global InsecureSkipVerify = true and self signed certificates [\#667](https://github.com/containous/traefik/issues/667)
- Docker exposedbydefault = false didn't work [\#663](https://github.com/containous/traefik/issues/663)
- swarm documentation needs update [\#656](https://github.com/containous/traefik/issues/656)
- \[ACME\] Auto SAN Detection [\#655](https://github.com/containous/traefik/issues/655)
- Fronting a domain with DNS A-record round-robin & ACME [\#654](https://github.com/containous/traefik/issues/654)
- Overriding toml configuration with environment variables [\#650](https://github.com/containous/traefik/issues/650)
- marathon provider exposedByDefault = false [\#647](https://github.com/containous/traefik/issues/647)
- Add status URL for service up checks [\#642](https://github.com/containous/traefik/issues/642)
- acme's storage file, containing private key, is word readable [\#638](https://github.com/containous/traefik/issues/638)
- wildcard domain with exclusions [\#633](https://github.com/containous/traefik/issues/633)
- Enable evenly distribution among backend [\#631](https://github.com/containous/traefik/issues/631)
- Traefik sporadically failing when proxying requests [\#615](https://github.com/containous/traefik/issues/615)
- TCP Proxy [\#608](https://github.com/containous/traefik/issues/608)
- How to use in Windows? [\#605](https://github.com/containous/traefik/issues/605)
- `ClientCAFiles` ignored [\#604](https://github.com/containous/traefik/issues/604)
- Let`s Encrypt enable in etcd [\#600](https://github.com/containous/traefik/issues/600)
- Support HTTP Basic Auth [\#599](https://github.com/containous/traefik/issues/599)
- Consul KV seem broken [\#587](https://github.com/containous/traefik/issues/587)
- HTTPS entryPoint not working [\#574](https://github.com/containous/traefik/issues/574)
- Traefik stuck when used as frontend for a streaming API [\#560](https://github.com/containous/traefik/issues/560)
- Exclude some frontends in consul catalog [\#555](https://github.com/containous/traefik/issues/555)
- Update docs with new Mesos provider [\#548](https://github.com/containous/traefik/issues/548)
- Can I use Traefik without a domain name? [\#539](https://github.com/containous/traefik/issues/539)
- docker run syntax in swarm example has changed [\#528](https://github.com/containous/traefik/issues/528)
- Priortities in 1.0.0 not behaving [\#506](https://github.com/containous/traefik/issues/506)
- Route by path [\#500](https://github.com/containous/traefik/issues/500)
- Secure WebSockets [\#467](https://github.com/containous/traefik/issues/467)
- Container IP Lost [\#375](https://github.com/containous/traefik/issues/375)
- Multiple routes support with Docker or Marathon labels [\#118](https://github.com/containous/traefik/issues/118)
**Merged pull requests:**
- Fix path case sensitive v1.1 [\#855](https://github.com/containous/traefik/pull/855) ([emilevauge](https://github.com/emilevauge))
- Fix golint in v1.1 [\#849](https://github.com/containous/traefik/pull/849) ([emilevauge](https://github.com/emilevauge))
- Fix Kubernetes watch leak [\#845](https://github.com/containous/traefik/pull/845) ([emilevauge](https://github.com/emilevauge))
- Pass Version, Codename and Date to crosscompiled [\#842](https://github.com/containous/traefik/pull/842) ([guilhem](https://github.com/guilhem))
- Add Nvd3 Dependency to fix UI / Dashboard [\#829](https://github.com/containous/traefik/pull/829) ([SantoDE](https://github.com/SantoDE))
- Fix mkdoc theme [\#823](https://github.com/containous/traefik/pull/823) ([emilevauge](https://github.com/emilevauge))
- Prepare release v1.1.0 rc4 [\#822](https://github.com/containous/traefik/pull/822) ([emilevauge](https://github.com/emilevauge))
- Check that we serve HTTP/2 [\#820](https://github.com/containous/traefik/pull/820) ([trecloux](https://github.com/trecloux))
- Fix multiple issues [\#814](https://github.com/containous/traefik/pull/814) ([emilevauge](https://github.com/emilevauge))
- Fix ACME renew & add version check [\#783](https://github.com/containous/traefik/pull/783) ([emilevauge](https://github.com/emilevauge))
- Use first port by default [\#782](https://github.com/containous/traefik/pull/782) ([guilhem](https://github.com/guilhem))
- Prepare release v1.1.0-rc3 [\#779](https://github.com/containous/traefik/pull/779) ([emilevauge](https://github.com/emilevauge))
- Fix ResponseRecorder Flush [\#776](https://github.com/containous/traefik/pull/776) ([emilevauge](https://github.com/emilevauge))
- Use sdnotify for systemd [\#768](https://github.com/containous/traefik/pull/768) ([guilhem](https://github.com/guilhem))
- Fix providers throttle duration doc [\#760](https://github.com/containous/traefik/pull/760) ([emilevauge](https://github.com/emilevauge))
- Fix mapstructure issue with anonymous slice [\#759](https://github.com/containous/traefik/pull/759) ([emilevauge](https://github.com/emilevauge))
- Fix multiple certificates using flag [\#758](https://github.com/containous/traefik/pull/758) ([emilevauge](https://github.com/emilevauge))
- Really fix deploy ghr... [\#748](https://github.com/containous/traefik/pull/748) ([emilevauge](https://github.com/emilevauge))
- Fixes deploy ghr [\#742](https://github.com/containous/traefik/pull/742) ([emilevauge](https://github.com/emilevauge))
- prepare v1.1.0-rc2 [\#740](https://github.com/containous/traefik/pull/740) ([emilevauge](https://github.com/emilevauge))
- Fix case sensitive host [\#733](https://github.com/containous/traefik/pull/733) ([emilevauge](https://github.com/emilevauge))
- Update Kubernetes examples [\#731](https://github.com/containous/traefik/pull/731) ([Starefossen](https://github.com/Starefossen))
- fIx marathon template with dots in ID [\#728](https://github.com/containous/traefik/pull/728) ([emilevauge](https://github.com/emilevauge))
- Fix networkMap construction in ListServices [\#724](https://github.com/containous/traefik/pull/724) ([vincentlepot](https://github.com/vincentlepot))
- Add basic compatibility with marathon-lb [\#720](https://github.com/containous/traefik/pull/720) ([guilhem](https://github.com/guilhem))
- Add Ed's video at ContainerCamp [\#717](https://github.com/containous/traefik/pull/717) ([emilevauge](https://github.com/emilevauge))
- Add documentation for Træfik on docker swarm mode [\#715](https://github.com/containous/traefik/pull/715) ([vdemeester](https://github.com/vdemeester))
- Remove duplicated link to Kubernetes.io in README.md [\#713](https://github.com/containous/traefik/pull/713) ([oscerd](https://github.com/oscerd))
- Show current version in web UI [\#709](https://github.com/containous/traefik/pull/709) ([vhf](https://github.com/vhf))
- Add support for docker healthcheck 👼 [\#708](https://github.com/containous/traefik/pull/708) ([vdemeester](https://github.com/vdemeester))
- Fix syntax in Swarm example. Resolves \#528 [\#707](https://github.com/containous/traefik/pull/707) ([billglover](https://github.com/billglover))
- Add HTTP compression [\#702](https://github.com/containous/traefik/pull/702) ([tuier](https://github.com/tuier))
- Carry PR 446 - Add sticky session support \(round two!\) [\#701](https://github.com/containous/traefik/pull/701) ([emilevauge](https://github.com/emilevauge))
- Remove unused endpoint when using constraints with Marathon provider [\#697](https://github.com/containous/traefik/pull/697) ([tuier](https://github.com/tuier))
- Replace imagelayers.io with microbadger [\#696](https://github.com/containous/traefik/pull/696) ([solidnerd](https://github.com/solidnerd))
- Selectable TLS Versions [\#690](https://github.com/containous/traefik/pull/690) ([dtomcej](https://github.com/dtomcej))
- Carry pr 439 [\#689](https://github.com/containous/traefik/pull/689) ([emilevauge](https://github.com/emilevauge))
- Disable gorilla/mux URL cleaning to prevent sending redirect [\#688](https://github.com/containous/traefik/pull/688) ([ydubreuil](https://github.com/ydubreuil))
- Some fixes [\#687](https://github.com/containous/traefik/pull/687) ([emilevauge](https://github.com/emilevauge))
- feat\(constraints\): Supports constraints for Marathon provider [\#686](https://github.com/containous/traefik/pull/686) ([tuier](https://github.com/tuier))
- Update docs to improve contribution setup [\#685](https://github.com/containous/traefik/pull/685) ([dtomcej](https://github.com/dtomcej))
- Add basic auth support for web backend [\#677](https://github.com/containous/traefik/pull/677) ([SantoDE](https://github.com/SantoDE))
- Document accepted values for logLevel. [\#676](https://github.com/containous/traefik/pull/676) ([jimmycuadra](https://github.com/jimmycuadra))
- If Marathon doesn't have healthcheck, assume it's ok [\#665](https://github.com/containous/traefik/pull/665) ([gomes](https://github.com/gomes))
- ACME: renew certificates 30 days before expiry [\#660](https://github.com/containous/traefik/pull/660) ([JayH5](https://github.com/JayH5))
- Update broken link and add a comment to sample config file [\#658](https://github.com/containous/traefik/pull/658) ([Yggdrasil](https://github.com/Yggdrasil))
- Add possibility to use BindPort IPAddress 👼 [\#657](https://github.com/containous/traefik/pull/657) ([vdemeester](https://github.com/vdemeester))
- Update marathon [\#648](https://github.com/containous/traefik/pull/648) ([emilevauge](https://github.com/emilevauge))
- Add backend features to docker [\#646](https://github.com/containous/traefik/pull/646) ([jangie](https://github.com/jangie))
- enable consul catalog to use maxconn [\#645](https://github.com/containous/traefik/pull/645) ([jangie](https://github.com/jangie))
- Adopt the Code Of Coduct from http://contributor-covenant.org [\#641](https://github.com/containous/traefik/pull/641) ([errm](https://github.com/errm))
- Use secure mode 600 instead of 644 for acme.json [\#639](https://github.com/containous/traefik/pull/639) ([discordianfish](https://github.com/discordianfish))
- docker clarification, fix dead urls, misc typos [\#637](https://github.com/containous/traefik/pull/637) ([djalal](https://github.com/djalal))
- add PING handler to dashboard API [\#630](https://github.com/containous/traefik/pull/630) ([jangie](https://github.com/jangie))
- Migrate to JobBackOff [\#628](https://github.com/containous/traefik/pull/628) ([emilevauge](https://github.com/emilevauge))
- Add long job exponential backoff [\#627](https://github.com/containous/traefik/pull/627) ([emilevauge](https://github.com/emilevauge))
- HA acme support [\#625](https://github.com/containous/traefik/pull/625) ([emilevauge](https://github.com/emilevauge))
- Bump go v1.7 [\#620](https://github.com/containous/traefik/pull/620) ([emilevauge](https://github.com/emilevauge))
- Make duration logging consistent [\#619](https://github.com/containous/traefik/pull/619) ([jangie](https://github.com/jangie))
- fix for nil clientTLS causing issue [\#617](https://github.com/containous/traefik/pull/617) ([jangie](https://github.com/jangie))
- Add ability for marathon provider to set maxconn values, loadbalancer algorithm, and circuit breaker expression [\#616](https://github.com/containous/traefik/pull/616) ([jangie](https://github.com/jangie))
- Make systemd unit installable [\#613](https://github.com/containous/traefik/pull/613) ([keis](https://github.com/keis))
- Merge v1.0.2 master [\#610](https://github.com/containous/traefik/pull/610) ([emilevauge](https://github.com/emilevauge))
- update staert and flaeg [\#609](https://github.com/containous/traefik/pull/609) ([cocap10](https://github.com/cocap10))
- \#504 Initial support for Docker 1.12 Swarm Mode [\#602](https://github.com/containous/traefik/pull/602) ([diegofernandes](https://github.com/diegofernandes))
- Add Host cert ACME generation [\#601](https://github.com/containous/traefik/pull/601) ([emilevauge](https://github.com/emilevauge))
- Fixed binary script so traefik version command doesn't just print default values [\#598](https://github.com/containous/traefik/pull/598) ([keiths-osc](https://github.com/keiths-osc))
- Name servers after thier pods [\#596](https://github.com/containous/traefik/pull/596) ([errm](https://github.com/errm))
- Fix Consul prefix [\#589](https://github.com/containous/traefik/pull/589) ([jippi](https://github.com/jippi))
- Prioritize kubernetes routes by path length [\#588](https://github.com/containous/traefik/pull/588) ([philk](https://github.com/philk))
- beautify help [\#580](https://github.com/containous/traefik/pull/580) ([cocap10](https://github.com/cocap10))
- Upgrade directives name since we use angular-ui-bootstrap [\#578](https://github.com/containous/traefik/pull/578) ([micaelmbagira](https://github.com/micaelmbagira))
- Fix basic docs for configuration of multiple rules [\#576](https://github.com/containous/traefik/pull/576) ([ajaegle](https://github.com/ajaegle))
- Fix k8s watch [\#573](https://github.com/containous/traefik/pull/573) ([errm](https://github.com/errm))
- Add requirements.txt for netlify [\#567](https://github.com/containous/traefik/pull/567) ([emilevauge](https://github.com/emilevauge))
- Merge v1.0.1 master [\#565](https://github.com/containous/traefik/pull/565) ([emilevauge](https://github.com/emilevauge))
- Move webui to FountainJS with Webpack [\#558](https://github.com/containous/traefik/pull/558) ([micaelmbagira](https://github.com/micaelmbagira))
- Add global InsecureSkipVerify option to disable certificate checking [\#557](https://github.com/containous/traefik/pull/557) ([stuart-c](https://github.com/stuart-c))
- Move version.go in its own package… [\#553](https://github.com/containous/traefik/pull/553) ([vdemeester](https://github.com/vdemeester))
- Upgrade libkermit and dependencies [\#552](https://github.com/containous/traefik/pull/552) ([vdemeester](https://github.com/vdemeester))
- Add command storeconfig [\#551](https://github.com/containous/traefik/pull/551) ([cocap10](https://github.com/cocap10))
- Add basic/digest auth [\#547](https://github.com/containous/traefik/pull/547) ([emilevauge](https://github.com/emilevauge))
- Bump node to 6 for webui [\#546](https://github.com/containous/traefik/pull/546) ([vdemeester](https://github.com/vdemeester))
- Bump golang to 1.6.3 [\#545](https://github.com/containous/traefik/pull/545) ([vdemeester](https://github.com/vdemeester))
- Fix typos [\#538](https://github.com/containous/traefik/pull/538) ([jimt](https://github.com/jimt))
- Kubernetes user-guide [\#519](https://github.com/containous/traefik/pull/519) ([errm](https://github.com/errm))
- Implement Kubernetes Selectors, minor kube endpoint fix [\#516](https://github.com/containous/traefik/pull/516) ([pnegahdar](https://github.com/pnegahdar))
- Carry \#358 : Option to disable expose of all docker containers [\#514](https://github.com/containous/traefik/pull/514) ([vdemeester](https://github.com/vdemeester))
- Remove traefik.frontend.value support in docker… [\#510](https://github.com/containous/traefik/pull/510) ([vdemeester](https://github.com/vdemeester))
- Use KvStores as global config sources [\#481](https://github.com/containous/traefik/pull/481) ([cocap10](https://github.com/cocap10))
- Add endpoint option to authenticate by client tls cert. [\#461](https://github.com/containous/traefik/pull/461) ([andersbetner](https://github.com/andersbetner))
- add mesos provider inspired by mesos-dns & marathon provider [\#353](https://github.com/containous/traefik/pull/353) ([skydjol](https://github.com/skydjol))
## [v1.1.0-rc4](https://github.com/containous/traefik/tree/v1.1.0-rc4) (2016-11-10)
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.0-rc3...v1.1.0-rc4)
**Implemented enhancements:**
- Feature Request: Enable Health checks to containers. [\#540](https://github.com/containous/traefik/issues/540)
**Fixed bugs:**
- Traefik stopped serving on upgrade to v1.1.0-rc3 [\#807](https://github.com/containous/traefik/issues/807)
- Traefik cannot read constraints from KV [\#794](https://github.com/containous/traefik/issues/794)
- HTTP2 - configuration [\#790](https://github.com/containous/traefik/issues/790)
- Allow multiple certificates on a single entrypoint when trying to use TLS? [\#747](https://github.com/containous/traefik/issues/747)
**Closed issues:**
- LoadBalancing doesn't work in single node Swarm-mode [\#815](https://github.com/containous/traefik/issues/815)
- cannot connect to docker daemon [\#813](https://github.com/containous/traefik/issues/813)
- Let's encrypt configuration not working [\#805](https://github.com/containous/traefik/issues/805)
- Question: Wildcard Host for Kubernetes Ingress [\#792](https://github.com/containous/traefik/issues/792)
- Multiple subdomains for Marathon backend. [\#785](https://github.com/containous/traefik/issues/785)
- traefik-1.1.0-rc1: build error [\#781](https://github.com/containous/traefik/issues/781)
- Multiple routes support with Docker or Marathon labels [\#118](https://github.com/containous/traefik/issues/118)
**Merged pull requests:**
- Prepare release v1.1.0 rc4 [\#822](https://github.com/containous/traefik/pull/822) ([emilevauge](https://github.com/emilevauge))
- Fix multiple issues [\#814](https://github.com/containous/traefik/pull/814) ([emilevauge](https://github.com/emilevauge))
- Fix ACME renew & add version check [\#783](https://github.com/containous/traefik/pull/783) ([emilevauge](https://github.com/emilevauge))
- Use first port by default [\#782](https://github.com/containous/traefik/pull/782) ([guilhem](https://github.com/guilhem))
## [v1.1.0-rc3](https://github.com/containous/traefik/tree/v1.1.0-rc3) (2016-10-26)
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.0-rc2...v1.1.0-rc3)
**Fixed bugs:**
- Cannot provide multiple certificates using flag [\#757](https://github.com/containous/traefik/issues/757)
- traefik \* Users: unsupported type: slice [\#743](https://github.com/containous/traefik/issues/743)
- \[Docker swarm mode\] The traefik.docker.network seems to have no effect [\#719](https://github.com/containous/traefik/issues/719)
- Case sensitive domain names breaks routing [\#562](https://github.com/containous/traefik/issues/562)
**Closed issues:**
- dependencies installation error [\#755](https://github.com/containous/traefik/issues/755)
- k8s provider w/ acme? [\#752](https://github.com/containous/traefik/issues/752)
- Documented ProvidersThrottleDuration value is invalid [\#741](https://github.com/containous/traefik/issues/741)
- Loadbalaning issues with traefik and Docker Swarm cluster [\#730](https://github.com/containous/traefik/issues/730)
- issues with marathon app ids containing a dot [\#726](https://github.com/containous/traefik/issues/726)
- How Routing traffic depending on path not domain in docker [\#706](https://github.com/containous/traefik/issues/706)
- Traefik crashes when using Consul catalog [\#699](https://github.com/containous/traefik/issues/699)
- File Watcher for rules does not work [\#683](https://github.com/containous/traefik/issues/683)
**Merged pull requests:**
- Fix ResponseRecorder Flush [\#776](https://github.com/containous/traefik/pull/776) ([emilevauge](https://github.com/emilevauge))
- Use sdnotify for systemd [\#768](https://github.com/containous/traefik/pull/768) ([guilhem](https://github.com/guilhem))
- Fix providers throttle duration doc [\#760](https://github.com/containous/traefik/pull/760) ([emilevauge](https://github.com/emilevauge))
- Fix mapstructure issue with anonymous slice [\#759](https://github.com/containous/traefik/pull/759) ([emilevauge](https://github.com/emilevauge))
- Fix multiple certificates using flag [\#758](https://github.com/containous/traefik/pull/758) ([emilevauge](https://github.com/emilevauge))
- Really fix deploy ghr... [\#748](https://github.com/containous/traefik/pull/748) ([emilevauge](https://github.com/emilevauge))
## [v1.1.0-rc2](https://github.com/containous/traefik/tree/v1.1.0-rc2) (2016-10-17) ## [v1.1.0-rc2](https://github.com/containous/traefik/tree/v1.1.0-rc2) (2016-10-17)
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.0-rc1...v1.1.0-rc2) [Full Changelog](https://github.com/containous/traefik/compare/v1.1.0-rc1...v1.1.0-rc2)

View file

@ -52,7 +52,7 @@ Run it and forget it!
- Circuit breakers on backends - Circuit breakers on backends
- Round Robin, rebalancer load-balancers - Round Robin, rebalancer load-balancers
- Rest Metrics - Rest Metrics
- [Tiny](https://imagelayers.io/?images=traefik) [official](https://hub.docker.com/r/_/traefik/) docker image included - [Tiny](https://microbadger.com/images/traefik) [official](https://hub.docker.com/r/_/traefik/) docker image included
- SSL backends support - SSL backends support
- SSL frontend support (with SNI) - SSL frontend support (with SNI)
- Clean AngularJS Web UI - Clean AngularJS Web UI
@ -159,9 +159,10 @@ Founded in 2014, Asteris creates next-generation infrastructure software for the
- Emile Vauge [@emilevauge](https://github.com/emilevauge) - Emile Vauge [@emilevauge](https://github.com/emilevauge)
- Vincent Demeester [@vdemeester](https://github.com/vdemeester) - Vincent Demeester [@vdemeester](https://github.com/vdemeester)
- Samuel Berthe [@samber](https://github.com/samber)
- Russell Clare [@Russell-IO](https://github.com/Russell-IO) - Russell Clare [@Russell-IO](https://github.com/Russell-IO)
- Ed Robinson [@errm](https://github.com/errm) - Ed Robinson [@errm](https://github.com/errm)
- Daniel Tomcej [@dtomcej](https://github.com/dtomcej)
- Manuel Laufenberg [@SantoDE](https://github.com/SantoDE)
## Credits ## Credits

View file

@ -137,6 +137,7 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl
leadership.Pool.AddGoCtx(func(ctx context.Context) { leadership.Pool.AddGoCtx(func(ctx context.Context) {
log.Infof("Starting ACME renew job...") log.Infof("Starting ACME renew job...")
defer log.Infof("Stopped ACME renew job...") defer log.Infof("Stopped ACME renew job...")
for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
@ -145,6 +146,7 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl
log.Errorf("Error renewing ACME certificate: %s", err.Error()) log.Errorf("Error renewing ACME certificate: %s", err.Error())
} }
} }
}
}) })
leadership.AddListener(func(elected bool) error { leadership.AddListener(func(elected bool) error {
@ -252,7 +254,6 @@ func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, checkOnDemandDomain func
needRegister = true needRegister = true
} }
log.Infof("buildACMEClient...")
a.client, err = a.buildACMEClient(account) a.client, err = a.buildACMEClient(account)
if err != nil { if err != nil {
return err return err
@ -270,7 +271,7 @@ func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, checkOnDemandDomain func
// The client has a URL to the current Let's Encrypt Subscriber // The client has a URL to the current Let's Encrypt Subscriber
// Agreement. The user will need to agree to it. // Agreement. The user will need to agree to it.
log.Infof("AgreeToTOS...") log.Debugf("AgreeToTOS...")
err = a.client.AgreeToTOS() err = a.client.AgreeToTOS()
if err != nil { if err != nil {
// Let's Encrypt Subscriber Agreement renew ? // Let's Encrypt Subscriber Agreement renew ?
@ -374,11 +375,6 @@ func (a *ACME) renewCertificates() error {
account := a.store.Get().(*Account) account := a.store.Get().(*Account)
for _, certificateResource := range account.DomainsCertificate.Certs { for _, certificateResource := range account.DomainsCertificate.Certs {
if certificateResource.needRenew() { if certificateResource.needRenew() {
transaction, object, err := a.store.Begin()
if err != nil {
return err
}
account = object.(*Account)
log.Debugf("Renewing certificate %+v", certificateResource.Domains) log.Debugf("Renewing certificate %+v", certificateResource.Domains)
renewedCert, err := a.client.RenewCertificate(acme.CertificateResource{ renewedCert, err := a.client.RenewCertificate(acme.CertificateResource{
Domain: certificateResource.Certificate.Domain, Domain: certificateResource.Certificate.Domain,
@ -399,6 +395,11 @@ func (a *ACME) renewCertificates() error {
PrivateKey: renewedCert.PrivateKey, PrivateKey: renewedCert.PrivateKey,
Certificate: renewedCert.Certificate, Certificate: renewedCert.Certificate,
} }
transaction, object, err := a.store.Begin()
if err != nil {
return err
}
account = object.(*Account)
err = account.DomainsCertificate.renewCertificates(renewedACMECert, certificateResource.Domains) err = account.DomainsCertificate.renewCertificates(renewedACMECert, certificateResource.Domains)
if err != nil { if err != nil {
log.Errorf("Error renewing certificate: %v", err) log.Errorf("Error renewing certificate: %v", err)

View file

@ -25,10 +25,11 @@ type TraefikConfiguration struct {
type GlobalConfiguration struct { type GlobalConfiguration struct {
GraceTimeOut int64 `short:"g" description:"Duration to give active requests a chance to finish during hot-reload"` GraceTimeOut int64 `short:"g" description:"Duration to give active requests a chance to finish during hot-reload"`
Debug bool `short:"d" description:"Enable debug mode"` Debug bool `short:"d" description:"Enable debug mode"`
CheckNewVersion bool `description:"Periodically check if a new version has been released"`
AccessLogsFile string `description:"Access logs file"` AccessLogsFile string `description:"Access logs file"`
TraefikLogsFile string `description:"Traefik logs file"` TraefikLogsFile string `description:"Traefik logs file"`
LogLevel string `short:"l" description:"Log level"` LogLevel string `short:"l" description:"Log level"`
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key'"` EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'"`
Cluster *types.Cluster `description:"Enable clustering"` Cluster *types.Cluster `description:"Enable clustering"`
Constraints types.Constraints `description:"Filter services by constraint, matching with service tags"` Constraints types.Constraints `description:"Filter services by constraint, matching with service tags"`
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL"` ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL"`
@ -264,14 +265,20 @@ func (certs *Certificates) String() string {
if len(*certs) == 0 { if len(*certs) == 0 {
return "" return ""
} }
return (*certs)[0].CertFile + "," + (*certs)[0].KeyFile var result []string
for _, certificate := range *certs {
result = append(result, certificate.CertFile+","+certificate.KeyFile)
}
return strings.Join(result, ";")
} }
// Set is the method to set the flag value, part of the flag.Value interface. // Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag. // Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it. // It's a comma-separated list, so we split it.
func (certs *Certificates) Set(value string) error { func (certs *Certificates) Set(value string) error {
files := strings.Split(value, ",") certificates := strings.Split(value, ";")
for _, certificate := range certificates {
files := strings.Split(certificate, ",")
if len(files) != 2 { if len(files) != 2 {
return errors.New("Bad certificates format: " + value) return errors.New("Bad certificates format: " + value)
} }
@ -279,6 +286,7 @@ func (certs *Certificates) Set(value string) error {
CertFile: files[0], CertFile: files[0],
KeyFile: files[1], KeyFile: files[1],
}) })
}
return nil return nil
} }
@ -325,7 +333,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
defaultMarathon.Watch = true defaultMarathon.Watch = true
defaultMarathon.Endpoint = "http://127.0.0.1:8080" defaultMarathon.Endpoint = "http://127.0.0.1:8080"
defaultMarathon.ExposedByDefault = true defaultMarathon.ExposedByDefault = true
defaultMarathon.Constraints = []types.Constraint{} defaultMarathon.Constraints = types.Constraints{}
defaultMarathon.DialerTimeout = 60 defaultMarathon.DialerTimeout = 60
defaultMarathon.KeepAlive = 10 defaultMarathon.KeepAlive = 10
@ -334,47 +342,47 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
defaultConsul.Watch = true defaultConsul.Watch = true
defaultConsul.Endpoint = "127.0.0.1:8500" defaultConsul.Endpoint = "127.0.0.1:8500"
defaultConsul.Prefix = "traefik" defaultConsul.Prefix = "traefik"
defaultConsul.Constraints = []types.Constraint{} defaultConsul.Constraints = types.Constraints{}
// default ConsulCatalog // default ConsulCatalog
var defaultConsulCatalog provider.ConsulCatalog var defaultConsulCatalog provider.ConsulCatalog
defaultConsulCatalog.Endpoint = "127.0.0.1:8500" defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
defaultConsulCatalog.Constraints = []types.Constraint{} defaultConsulCatalog.Constraints = types.Constraints{}
// default Etcd // default Etcd
var defaultEtcd provider.Etcd var defaultEtcd provider.Etcd
defaultEtcd.Watch = true defaultEtcd.Watch = true
defaultEtcd.Endpoint = "127.0.0.1:2379" defaultEtcd.Endpoint = "127.0.0.1:2379"
defaultEtcd.Prefix = "/traefik" defaultEtcd.Prefix = "/traefik"
defaultEtcd.Constraints = []types.Constraint{} defaultEtcd.Constraints = types.Constraints{}
//default Zookeeper //default Zookeeper
var defaultZookeeper provider.Zookepper var defaultZookeeper provider.Zookepper
defaultZookeeper.Watch = true defaultZookeeper.Watch = true
defaultZookeeper.Endpoint = "127.0.0.1:2181" defaultZookeeper.Endpoint = "127.0.0.1:2181"
defaultZookeeper.Prefix = "/traefik" defaultZookeeper.Prefix = "/traefik"
defaultZookeeper.Constraints = []types.Constraint{} defaultZookeeper.Constraints = types.Constraints{}
//default Boltdb //default Boltdb
var defaultBoltDb provider.BoltDb var defaultBoltDb provider.BoltDb
defaultBoltDb.Watch = true defaultBoltDb.Watch = true
defaultBoltDb.Endpoint = "127.0.0.1:4001" defaultBoltDb.Endpoint = "127.0.0.1:4001"
defaultBoltDb.Prefix = "/traefik" defaultBoltDb.Prefix = "/traefik"
defaultBoltDb.Constraints = []types.Constraint{} defaultBoltDb.Constraints = types.Constraints{}
//default Kubernetes //default Kubernetes
var defaultKubernetes provider.Kubernetes var defaultKubernetes provider.Kubernetes
defaultKubernetes.Watch = true defaultKubernetes.Watch = true
defaultKubernetes.Endpoint = "" defaultKubernetes.Endpoint = ""
defaultKubernetes.LabelSelector = "" defaultKubernetes.LabelSelector = ""
defaultKubernetes.Constraints = []types.Constraint{} defaultKubernetes.Constraints = types.Constraints{}
// default Mesos // default Mesos
var defaultMesos provider.Mesos var defaultMesos provider.Mesos
defaultMesos.Watch = true defaultMesos.Watch = true
defaultMesos.Endpoint = "http://127.0.0.1:5050" defaultMesos.Endpoint = "http://127.0.0.1:5050"
defaultMesos.ExposedByDefault = true defaultMesos.ExposedByDefault = true
defaultMesos.Constraints = []types.Constraint{} defaultMesos.Constraints = types.Constraints{}
defaultConfiguration := GlobalConfiguration{ defaultConfiguration := GlobalConfiguration{
Docker: &defaultDocker, Docker: &defaultDocker,
@ -404,10 +412,11 @@ func NewTraefikConfiguration() *TraefikConfiguration {
TraefikLogsFile: "", TraefikLogsFile: "",
LogLevel: "ERROR", LogLevel: "ERROR",
EntryPoints: map[string]*EntryPoint{}, EntryPoints: map[string]*EntryPoint{},
Constraints: []types.Constraint{}, Constraints: types.Constraints{},
DefaultEntryPoints: []string{}, DefaultEntryPoints: []string{},
ProvidersThrottleDuration: time.Duration(2 * time.Second), ProvidersThrottleDuration: time.Duration(2 * time.Second),
MaxIdleConnsPerHost: 200, MaxIdleConnsPerHost: 200,
CheckNewVersion: true,
}, },
ConfigFile: "", ConfigFile: "",
} }

View file

@ -2,6 +2,7 @@
Description=Traefik Description=Traefik
[Service] [Service]
Type=notify
ExecStart=/usr/bin/traefik --configFile=/etc/traefik.toml ExecStart=/usr/bin/traefik --configFile=/etc/traefik.toml
Restart=on-failure Restart=on-failure

View file

@ -40,10 +40,15 @@ Run it and forget it!
You can have a quick look at Træfɪk in this [Katacoda tutorial](https://www.katacoda.com/courses/traefik/deploy-load-balancer) that shows how to load balance requests between multiple Docker containers. You can have a quick look at Træfɪk in this [Katacoda tutorial](https://www.katacoda.com/courses/traefik/deploy-load-balancer) that shows how to load balance requests between multiple Docker containers.
Here is a talk (in french) given by [Emile Vauge](https://github.com/emilevauge) at the [Devoxx France 2016](http://www.devoxx.fr) conference. Here is a talk given by [Ed Robinson](https://github.com/errm) at the [ContainerCamp UK](https://container.camp) conference.
You will learn fundamental Træfɪk features and see some demos with Docker, Mesos/Marathon and Lets'Encrypt. You will learn fundamental Træfɪk features and see some demos with Kubernetes.
[![Traefik Devoxx France](https://img.youtube.com/vi/QvAz9mVx5TI/0.jpg)](https://www.youtube.com/watch?v=QvAz9mVx5TI) [![Traefik ContainerCamp UK](http://img.youtube.com/vi/aFtpIShV60I/0.jpg)](https://www.youtube.com/watch?v=aFtpIShV60I)
Here is a talk (in French) given by [Emile Vauge](https://github.com/emilevauge) at the [Devoxx France 2016](http://www.devoxx.fr) conference.
You will learn fundamental Træfɪk features and see some demos with Docker, Mesos/Marathon and Let's Encrypt.
[![Traefik Devoxx France](http://img.youtube.com/vi/QvAz9mVx5TI/0.jpg)](http://www.youtube.com/watch?v=QvAz9mVx5TI)
## Get it ## Get it

View file

@ -9,6 +9,28 @@
# Global configuration # Global configuration
################################################################ ################################################################
# Timeout in seconds.
# Duration to give active requests a chance to finish during hot-reloads
#
# Optional
# Default: 10
#
# graceTimeOut = 10
# Enable debug mode
#
# Optional
# Default: false
#
# debug = true
# Periodically check if a new version has been released
#
# Optional
# Default: true
#
# checkNewVersion = false
# Traefik logs file # Traefik logs file
# If not defined, logs to stdout # If not defined, logs to stdout
# #
@ -31,14 +53,14 @@
# #
# logLevel = "ERROR" # logLevel = "ERROR"
# Backends throttle duration: minimum duration between 2 events from providers # Backends throttle duration: minimum duration in seconds between 2 events from providers
# before applying a new configuration. It avoids unnecessary reloads if multiples events # before applying a new configuration. It avoids unnecessary reloads if multiples events
# are sent in a short amount of time. # are sent in a short amount of time.
# #
# Optional # Optional
# Default: "2s" # Default: "2"
# #
# ProvidersThrottleDuration = "5s" # ProvidersThrottleDuration = "5"
# If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. # If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used.
# If you encounter 'too many open files' errors, you can either change this value, or change `ulimit` value. # If you encounter 'too many open files' errors, you can either change this value, or change `ulimit` value.
@ -493,7 +515,7 @@ address = ":8080"
# To enable digest auth on the webui # To enable digest auth on the webui
# with 2 user/realm/pass: test:traefik:test and test2:traefik:test2 # with 2 user/realm/pass: test:traefik:test and test2:traefik:test2
# You can use htdigest to generate those ones # You can use htdigest to generate those ones
# [web.auth.basic] # [web.auth.digest]
# users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"] # users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
``` ```

56
glide.lock generated
View file

@ -1,5 +1,5 @@
hash: 3ff2f92356bc5d286ce4d72835d5ace63c43cc591e561fd2d557e8dc8abd1672 hash: 26bdc224454872acf1a9a58e0f4c33442a807087286043ed7d8d6640f1a2e8fc
updated: 2016-11-17T17:17:58.806741449Z updated: 2016-12-05T21:21:43.691375582+01:00
imports: imports:
- name: github.com/abbot/go-http-auth - name: github.com/abbot/go-http-auth
version: cb4372376e1e00e9f6ab9ec142e029302c9e7140 version: cb4372376e1e00e9f6ab9ec142e029302c9e7140
@ -10,7 +10,7 @@ imports:
- name: github.com/ArthurHlt/gominlog - name: github.com/ArthurHlt/gominlog
version: 068c01ce147ad68fca25ef3fa29ae5395ae273ab version: 068c01ce147ad68fca25ef3fa29ae5395ae273ab
- name: github.com/blang/semver - name: github.com/blang/semver
version: 60ec3488bfea7cca02b021d106d9911120d25fe9 version: 3a37c301dda64cbe17f16f661b4c976803c0e2d2
- name: github.com/boltdb/bolt - name: github.com/boltdb/bolt
version: f4c032d907f61f08dba2d719c58f108a1abb8e81 version: f4c032d907f61f08dba2d719c58f108a1abb8e81
- name: github.com/BurntSushi/toml - name: github.com/BurntSushi/toml
@ -21,8 +21,6 @@ imports:
- fun - fun
- name: github.com/cenk/backoff - name: github.com/cenk/backoff
version: 8edc80b07f38c27352fb186d971c628a6c32552b version: 8edc80b07f38c27352fb186d971c628a6c32552b
- name: github.com/cloudfoundry-incubator/candiedyaml
version: 99c3df83b51532e3615f851d8c2dbb638f5313bf
- name: github.com/codahale/hdrhistogram - name: github.com/codahale/hdrhistogram
version: 9208b142303c12d8899bae836fd524ac9338b4fd version: 9208b142303c12d8899bae836fd524ac9338b4fd
- name: github.com/codegangsta/cli - name: github.com/codegangsta/cli
@ -34,7 +32,7 @@ imports:
- name: github.com/containous/mux - name: github.com/containous/mux
version: a819b77bba13f0c0cbe36e437bc2e948411b3996 version: a819b77bba13f0c0cbe36e437bc2e948411b3996
- name: github.com/containous/staert - name: github.com/containous/staert
version: 92329254783dc01174f03302d51d7cf2c9ff84cf version: 1e26a71803e428fd933f5f9c8e50a26878f53147
- name: github.com/coreos/etcd - name: github.com/coreos/etcd
version: c400d05d0aa73e21e431c16145e558d624098018 version: c400d05d0aa73e21e431c16145e558d624098018
subpackages: subpackages:
@ -44,13 +42,17 @@ imports:
- pkg/pathutil - pkg/pathutil
- pkg/types - pkg/types
- name: github.com/coreos/go-oidc - name: github.com/coreos/go-oidc
version: 16c5ecc505f1efa0fe4685826fd9962c4d137e87 version: dedb650fb29c39c2f21aa88c1e4cec66da8754d1
subpackages: subpackages:
- http - http
- jose - jose
- key - key
- oauth2 - oauth2
- oidc - oidc
- name: github.com/coreos/go-systemd
version: 43e4800a6165b4e02bb2a36673c54b230d6f7b26
subpackages:
- daemon
- name: github.com/coreos/pkg - name: github.com/coreos/pkg
version: 2c77715c4df99b5420ffcae14ead08f52104065d version: 2c77715c4df99b5420ffcae14ead08f52104065d
subpackages: subpackages:
@ -174,13 +176,13 @@ imports:
- name: github.com/gambol99/go-marathon - name: github.com/gambol99/go-marathon
version: a558128c87724cd7430060ef5aedf39f83937f55 version: a558128c87724cd7430060ef5aedf39f83937f55
- name: github.com/ghodss/yaml - name: github.com/ghodss/yaml
version: aa0c862057666179de291b67d9f093d12b5a8473 version: a54de18a07046d8c4b26e9327698a2ebb9285b36
- name: github.com/go-openapi/jsonpointer - name: github.com/go-openapi/jsonpointer
version: 8d96a2dc61536b690bd36b2e9df0b3c0b62825b2 version: 8d96a2dc61536b690bd36b2e9df0b3c0b62825b2
- name: github.com/go-openapi/jsonreference - name: github.com/go-openapi/jsonreference
version: 36d33bfe519efae5632669801b180bf1a245da3b version: 36d33bfe519efae5632669801b180bf1a245da3b
- name: github.com/go-openapi/spec - name: github.com/go-openapi/spec
version: d1c18b339aece4b16ead6d253b85b6ad7180ea54 version: f7ae86df5bc115a2744343016c789a89f065a4bd
- name: github.com/go-openapi/swag - name: github.com/go-openapi/swag
version: 3b6d86cd965820f968760d5d419cb4add096bdd7 version: 3b6d86cd965820f968760d5d419cb4add096bdd7
- name: github.com/gogo/protobuf - name: github.com/gogo/protobuf
@ -194,22 +196,28 @@ imports:
version: 5677a0e3d5e89854c9974e1256839ee23f8233ca version: 5677a0e3d5e89854c9974e1256839ee23f8233ca
subpackages: subpackages:
- proto - proto
- name: github.com/google/go-github
version: 55263f30529cb06f5b478efc333390b791cfe3b1
subpackages:
- github
- name: github.com/google/go-querystring - name: github.com/google/go-querystring
version: 9235644dd9e52eeae6fa48efd539fdc351a0af53 version: 9235644dd9e52eeae6fa48efd539fdc351a0af53
subpackages: subpackages:
- query - query
- name: github.com/google/gofuzz - name: github.com/google/gofuzz
version: fd52762d25a41827db7ef64c43756fd4b9f7e382 version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
- name: github.com/gorilla/context - name: github.com/gorilla/context
version: 14f550f51af52180c2eefed15e5fd18d63c0a64a version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
- name: github.com/hashicorp/consul - name: github.com/hashicorp/consul
version: d8e2fb7dd594163e25a89bc52c1a4613f5c5bfb8 version: d8e2fb7dd594163e25a89bc52c1a4613f5c5bfb8
subpackages: subpackages:
- api - api
- name: github.com/hashicorp/go-cleanhttp - name: github.com/hashicorp/go-cleanhttp
version: ad28ea4487f05916463e2423a55166280e8254b5 version: ad28ea4487f05916463e2423a55166280e8254b5
- name: github.com/hashicorp/go-version
version: e96d3840402619007766590ecea8dd7af1292276
- name: github.com/hashicorp/serf - name: github.com/hashicorp/serf
version: 598c54895cc5a7b1a24a398d635e8c0ea0959870 version: b03bf85930b2349eb04b97c8fac437495296e3e7
subpackages: subpackages:
- coordinate - coordinate
- name: github.com/jarcoal/httpmock - name: github.com/jarcoal/httpmock
@ -257,19 +265,23 @@ imports:
- name: github.com/miekg/dns - name: github.com/miekg/dns
version: 5d001d020961ae1c184f9f8152fdc73810481677 version: 5d001d020961ae1c184f9f8152fdc73810481677
- name: github.com/mitchellh/mapstructure - name: github.com/mitchellh/mapstructure
version: ca63d7c062ee3c9f34db231e352b60012b4fd0c1 version: f3009df150dadf309fdee4a54ed65c124afad715
- name: github.com/NYTimes/gziphandler - name: github.com/NYTimes/gziphandler
version: f6438dbf4a82c56684964b03956aa727b0d7816b version: f6438dbf4a82c56684964b03956aa727b0d7816b
- name: github.com/ogier/pflag - name: github.com/ogier/pflag
version: 45c278ab3607870051a2ea9040bb85fcb8557481 version: 45c278ab3607870051a2ea9040bb85fcb8557481
- name: github.com/opencontainers/runc - name: github.com/opencontainers/runc
version: ba1568de399395774ad84c2ace65937814c542ed version: 02f8fa7863dd3f82909a73e2061897828460d52f
subpackages: subpackages:
- libcontainer/user - libcontainer/user
- name: github.com/parnurzeal/gorequest - name: github.com/parnurzeal/gorequest
version: e30af16d4e485943aab0b0885ad6bdbb8c0d3dc7 version: e30af16d4e485943aab0b0885ad6bdbb8c0d3dc7
- name: github.com/pborman/uuid - name: github.com/pborman/uuid
version: 3d4f2ba23642d3cfd06bd4b54cf03d99d95c0f1b version: 3d4f2ba23642d3cfd06bd4b54cf03d99d95c0f1b
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/PuerkitoBio/purell - name: github.com/PuerkitoBio/purell
version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4 version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4
- name: github.com/PuerkitoBio/urlesc - name: github.com/PuerkitoBio/urlesc
@ -291,7 +303,7 @@ imports:
- name: github.com/stretchr/objx - name: github.com/stretchr/objx
version: cbeaeb16a013161a98496fad62933b1d21786672 version: cbeaeb16a013161a98496fad62933b1d21786672
- name: github.com/stretchr/testify - name: github.com/stretchr/testify
version: b8dc1cecf15bdaf1988d9e87aa7cd98d899a06d6 version: 976c720a22c8eb4eb6a0b4348ad85ad12491a506
subpackages: subpackages:
- assert - assert
- mock - mock
@ -305,10 +317,12 @@ imports:
- codec - codec
- name: github.com/unrolled/render - name: github.com/unrolled/render
version: 526faf80cd4b305bb8134abea8d20d5ced74faa6 version: 526faf80cd4b305bb8134abea8d20d5ced74faa6
- name: github.com/urfave/negroni
version: e0e50f7dc431c043cb33f91b09c3419d48b7cff5
- name: github.com/vdemeester/docker-events - name: github.com/vdemeester/docker-events
version: be74d4929ec1ad118df54349fda4b0cba60f849b version: be74d4929ec1ad118df54349fda4b0cba60f849b
- name: github.com/vulcand/oxy - name: github.com/vulcand/oxy
version: 4298f24d572dc554eb984f2ffdf6bdd54d4bd613 version: fcc76b52eb8568540a020b7a99e854d9d752b364
repo: https://github.com/containous/oxy.git repo: https://github.com/containous/oxy.git
vcs: git vcs: git
subpackages: subpackages:
@ -363,7 +377,7 @@ imports:
- unix - unix
- windows - windows
- name: golang.org/x/text - name: golang.org/x/text
version: a263ba8db058568bb9beba166777d9c9dbe75d68 version: 5c6cf4f9a2357d38515014cea8c488ed22bdab90
subpackages: subpackages:
- transform - transform
- unicode/norm - unicode/norm
@ -390,7 +404,7 @@ imports:
- name: gopkg.in/inf.v0 - name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/mgo.v2 - name: gopkg.in/mgo.v2
version: 29cc868a5ca65f401ff318143f9408d02f4799cc version: 22287bab4379e1fbf6002fb4eb769888f3fb224c
subpackages: subpackages:
- bson - bson
- name: gopkg.in/square/go-jose.v1 - name: gopkg.in/square/go-jose.v1
@ -398,6 +412,8 @@ imports:
subpackages: subpackages:
- cipher - cipher
- json - json
- name: gopkg.in/yaml.v2
version: bef53efd0c76e49e6de55ead051f886bea7e9420
- name: k8s.io/client-go - name: k8s.io/client-go
version: 843f7c4f28b1f647f664f883697107d5c02c5acc version: 843f7c4f28b1f647f664f883697107d5c02c5acc
subpackages: subpackages:
@ -509,6 +525,8 @@ testImports:
version: fa152c58bc15761d0200cb75fe958b89a9d4888e version: fa152c58bc15761d0200cb75fe958b89a9d4888e
subpackages: subpackages:
- winterm - winterm
- name: github.com/cloudfoundry-incubator/candiedyaml
version: 99c3df83b51532e3615f851d8c2dbb638f5313bf
- name: github.com/docker/libcompose - name: github.com/docker/libcompose
version: d1876c1d68527a49c0aac22a0b161acc7296b740 version: d1876c1d68527a49c0aac22a0b161acc7296b740
subpackages: subpackages:
@ -529,7 +547,7 @@ testImports:
- name: github.com/flynn/go-shlex - name: github.com/flynn/go-shlex
version: 3f9db97f856818214da2e1057f8ad84803971cff version: 3f9db97f856818214da2e1057f8ad84803971cff
- name: github.com/go-check/check - name: github.com/go-check/check
version: 11d3bc7aa68e238947792f30573146a3231fc0f1 version: 4f90aeace3a26ad7021961c297b22c42160c7b25
- name: github.com/gorilla/mux - name: github.com/gorilla/mux
version: e444e69cbd2e2e3e0749a2f3c717cec491552bbf version: e444e69cbd2e2e3e0749a2f3c717cec491552bbf
- name: github.com/libkermit/compose - name: github.com/libkermit/compose

View file

@ -6,11 +6,11 @@ import:
- fun - fun
- package: github.com/Sirupsen/logrus - package: github.com/Sirupsen/logrus
- package: github.com/cenk/backoff - package: github.com/cenk/backoff
- package: github.com/codegangsta/negroni - package: github.com/urfave/negroni
- package: github.com/containous/flaeg - package: github.com/containous/flaeg
version: a731c034dda967333efce5f8d276aeff11f8ff87 version: a731c034dda967333efce5f8d276aeff11f8ff87
- package: github.com/vulcand/oxy - package: github.com/vulcand/oxy
version: 4298f24d572dc554eb984f2ffdf6bdd54d4bd613 version: fcc76b52eb8568540a020b7a99e854d9d752b364
repo: https://github.com/containous/oxy.git repo: https://github.com/containous/oxy.git
vcs: git vcs: git
subpackages: subpackages:
@ -21,7 +21,7 @@ import:
- stream - stream
- utils - utils
- package: github.com/containous/staert - package: github.com/containous/staert
version: 92329254783dc01174f03302d51d7cf2c9ff84cf version: 1e26a71803e428fd933f5f9c8e50a26878f53147
- package: github.com/docker/engine-api - package: github.com/docker/engine-api
version: 62043eb79d581a32ea849645277023c550732e52 version: 62043eb79d581a32ea849645277023c550732e52
subpackages: subpackages:
@ -103,3 +103,11 @@ import:
- package: github.com/ArthurHlt/go-eureka-client - package: github.com/ArthurHlt/go-eureka-client
subpackages: subpackages:
- eureka - eureka
- package: github.com/mitchellh/mapstructure
version: f3009df150dadf309fdee4a54ed65c124afad715
- package: github.com/coreos/go-systemd
version: v12
subpackages:
- daemon
- package: github.com/google/go-github
- package: github.com/hashicorp/go-version

View file

@ -30,6 +30,7 @@ func (s *HTTPSSuite) TestWithSNIConfigHandshake(c *check.C) {
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
ServerName: "snitest.com", ServerName: "snitest.com",
NextProtos: []string{"h2", "http/1.1"},
} }
conn, err := tls.Dial("tcp", "127.0.0.1:4443", tlsConfig) conn, err := tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server")) c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server"))
@ -41,6 +42,9 @@ func (s *HTTPSSuite) TestWithSNIConfigHandshake(c *check.C) {
cs := conn.ConnectionState() cs := conn.ConnectionState()
err = cs.PeerCertificates[0].VerifyHostname("snitest.com") err = cs.PeerCertificates[0].VerifyHostname("snitest.com")
c.Assert(err, checker.IsNil, check.Commentf("certificate did not match SNI servername")) c.Assert(err, checker.IsNil, check.Commentf("certificate did not match SNI servername"))
proto := conn.ConnectionState().NegotiatedProtocol
c.Assert(proto, checker.Equals, "h2")
} }
// TestWithSNIConfigRoute involves a client sending HTTPS requests with // TestWithSNIConfigRoute involves a client sending HTTPS requests with

View file

@ -9,6 +9,13 @@ import (
"net/http" "net/http"
) )
var (
_ http.ResponseWriter = &ResponseRecorder{}
_ http.Hijacker = &ResponseRecorder{}
_ http.Flusher = &ResponseRecorder{}
_ http.CloseNotifier = &ResponseRecorder{}
)
// Retry is a middleware that retries requests // Retry is a middleware that retries requests
type Retry struct { type Retry struct {
attempts int attempts int
@ -52,6 +59,7 @@ type ResponseRecorder struct {
Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
responseWriter http.ResponseWriter responseWriter http.ResponseWriter
err error
} }
// NewRecorder returns an initialized ResponseRecorder. // NewRecorder returns an initialized ResponseRecorder.
@ -75,10 +83,10 @@ func (rw *ResponseRecorder) Header() http.Header {
// Write always succeeds and writes to rw.Body, if not nil. // Write always succeeds and writes to rw.Body, if not nil.
func (rw *ResponseRecorder) Write(buf []byte) (int, error) { func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
if rw.Body != nil { if rw.err != nil {
return rw.Body.Write(buf) return 0, rw.err
} }
return 0, nil return rw.Body.Write(buf)
} }
// WriteHeader sets rw.Code. // WriteHeader sets rw.Code.
@ -90,3 +98,24 @@ func (rw *ResponseRecorder) WriteHeader(code int) {
func (rw *ResponseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (rw *ResponseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return rw.responseWriter.(http.Hijacker).Hijack() return rw.responseWriter.(http.Hijacker).Hijack()
} }
// CloseNotify returns a channel that receives at most a
// single value (true) when the client connection has gone
// away.
func (rw *ResponseRecorder) CloseNotify() <-chan bool {
return rw.responseWriter.(http.CloseNotifier).CloseNotify()
}
// Flush sends any buffered data to the client.
func (rw *ResponseRecorder) Flush() {
_, err := rw.responseWriter.Write(rw.Body.Bytes())
if err != nil {
log.Errorf("Error writing response in ResponseRecorder: %s", err)
rw.err = err
}
rw.Body.Reset()
flusher, ok := rw.responseWriter.(http.Flusher)
if ok {
flusher.Flush()
}
}

View file

@ -17,7 +17,7 @@ type BoltDb struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *BoltDb) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *BoltDb) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
store, err := provider.CreateStore() store, err := provider.CreateStore()
if err != nil { if err != nil {
return fmt.Errorf("Failed to Connect to KV store: %v", err) return fmt.Errorf("Failed to Connect to KV store: %v", err)

View file

@ -17,7 +17,7 @@ type Consul struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Consul) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Consul) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
store, err := provider.CreateStore() store, err := provider.CreateStore()
if err != nil { if err != nil {
return fmt.Errorf("Failed to Connect to KV store: %v", err) return fmt.Errorf("Failed to Connect to KV store: %v", err)

View file

@ -317,7 +317,7 @@ func (provider *ConsulCatalog) watch(configurationChan chan<- types.ConfigMessag
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *ConsulCatalog) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *ConsulCatalog) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
config := api.DefaultConfig() config := api.DefaultConfig()
config.Address = provider.Endpoint config.Address = provider.Endpoint
client, err := api.NewClient(config) client, err := api.NewClient(config)

View file

@ -61,7 +61,7 @@ func TestConsulCatalogGetAttribute(t *testing.T) {
"traefik.backend.weight=42", "traefik.backend.weight=42",
}, },
key: "backend.weight", key: "backend.weight",
defaultValue: "", defaultValue: "0",
expected: "42", expected: "42",
}, },
{ {
@ -70,8 +70,8 @@ func TestConsulCatalogGetAttribute(t *testing.T) {
"traefik.backend.wei=42", "traefik.backend.wei=42",
}, },
key: "backend.weight", key: "backend.weight",
defaultValue: "", defaultValue: "0",
expected: "", expected: "0",
}, },
} }

View file

@ -113,7 +113,7 @@ func (provider *Docker) createClient() (client.APIClient, error) {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
provider.Constraints = append(provider.Constraints, constraints...) provider.Constraints = append(provider.Constraints, constraints...)
// TODO register this routine in pool, and watch for stop channel // TODO register this routine in pool, and watch for stop channel
safe.Go(func() { safe.Go(func() {
@ -363,10 +363,6 @@ func (provider *Docker) containerFilter(container dockerData) bool {
log.Debugf("Filtering container without port and no traefik.port label %s", container.Name) log.Debugf("Filtering container without port and no traefik.port label %s", container.Name)
return false return false
} }
if len(container.NetworkSettings.Ports) > 1 && err != nil {
log.Debugf("Filtering container with more than 1 port and no traefik.port label %s", container.Name)
return false
}
if !isContainerEnabled(container, provider.ExposedByDefault) { if !isContainerEnabled(container, provider.ExposedByDefault) {
log.Debugf("Filtering disabled container %s", container.Name) log.Debugf("Filtering disabled container %s", container.Name)
@ -405,7 +401,7 @@ func (provider *Docker) getFrontendRule(container dockerData) string {
func (provider *Docker) getBackend(container dockerData) string { func (provider *Docker) getBackend(container dockerData) string {
if label, err := getLabel(container, "traefik.backend"); err == nil { if label, err := getLabel(container, "traefik.backend"); err == nil {
return label return normalize(label)
} }
return normalize(container.Name) return normalize(container.Name)
} }
@ -458,7 +454,7 @@ func (provider *Docker) getWeight(container dockerData) string {
if label, err := getLabel(container, "traefik.weight"); err == nil { if label, err := getLabel(container, "traefik.weight"); err == nil {
return label return label
} }
return "1" return "0"
} }
func (provider *Docker) getSticky(container dockerData) string { func (provider *Docker) getSticky(container dockerData) string {
@ -563,6 +559,10 @@ func parseContainer(container dockertypes.ContainerJSON) dockerData {
if container.ContainerJSONBase.HostConfig != nil { if container.ContainerJSONBase.HostConfig != nil {
dockerData.NetworkSettings.NetworkMode = container.ContainerJSONBase.HostConfig.NetworkMode dockerData.NetworkSettings.NetworkMode = container.ContainerJSONBase.HostConfig.NetworkMode
} }
if container.State != nil && container.State.Health != nil {
dockerData.Health = container.State.Health.Status
}
} }
if container.Config != nil && container.Config.Labels != nil { if container.Config != nil && container.Config.Labels != nil {
@ -586,10 +586,6 @@ func parseContainer(container dockertypes.ContainerJSON) dockerData {
} }
if container.State != nil && container.State.Health != nil {
dockerData.Health = container.State.Health.Status
}
return dockerData return dockerData
} }

View file

@ -390,6 +390,27 @@ func TestDockerGetPort(t *testing.T) {
}, },
expected: "8080", expected: "8080",
}, },
{
container: docker.ContainerJSON{
ContainerJSONBase: &docker.ContainerJSONBase{
Name: "test-multi-ports",
},
Config: &container.Config{
Labels: map[string]string{
"traefik.port": "8080",
},
},
NetworkSettings: &docker.NetworkSettings{
NetworkSettingsBase: docker.NetworkSettingsBase{
Ports: nat.PortMap{
"8080/tcp": {},
"80/tcp": {},
},
},
},
},
expected: "8080",
},
} }
for _, e := range containers { for _, e := range containers {
@ -415,7 +436,7 @@ func TestDockerGetWeight(t *testing.T) {
}, },
Config: &container.Config{}, Config: &container.Config{},
}, },
expected: "1", expected: "0",
}, },
{ {
container: docker.ContainerJSON{ container: docker.ContainerJSON{
@ -735,7 +756,7 @@ func TestDockerTraefikFilter(t *testing.T) {
{ {
container: docker.ContainerJSON{ container: docker.ContainerJSON{
ContainerJSONBase: &docker.ContainerJSONBase{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container", Name: "container-multi-ports",
}, },
Config: &container.Config{}, Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
@ -748,7 +769,7 @@ func TestDockerTraefikFilter(t *testing.T) {
}, },
}, },
exposedByDefault: true, exposedByDefault: true,
expected: false, expected: true,
}, },
{ {
container: docker.ContainerJSON{ container: docker.ContainerJSON{
@ -951,7 +972,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"server-test": { "server-test": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
}, },
CircuitBreaker: nil, CircuitBreaker: nil,
@ -1033,11 +1054,11 @@ func TestDockerLoadDockerConfig(t *testing.T) {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"server-test1": { "server-test1": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
"server-test2": { "server-test2": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
}, },
CircuitBreaker: nil, CircuitBreaker: nil,
@ -1091,7 +1112,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"server-test1": { "server-test1": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
}, },
CircuitBreaker: &types.CircuitBreaker{ CircuitBreaker: &types.CircuitBreaker{
@ -1506,7 +1527,7 @@ func TestSwarmGetWeight(t *testing.T) {
}, },
}, },
}, },
expected: "1", expected: "0",
networks: map[string]*docker.NetworkResource{}, networks: map[string]*docker.NetworkResource{},
}, },
{ {
@ -2034,7 +2055,7 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"server-test": { "server-test": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
}, },
CircuitBreaker: nil, CircuitBreaker: nil,
@ -2122,11 +2143,11 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"server-test1": { "server-test1": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
"server-test2": { "server-test2": {
URL: "http://127.0.0.1:80", URL: "http://127.0.0.1:80",
Weight: 1, Weight: 0,
}, },
}, },
CircuitBreaker: nil, CircuitBreaker: nil,

View file

@ -17,7 +17,7 @@ type Etcd struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Etcd) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Etcd) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
store, err := provider.CreateStore() store, err := provider.CreateStore()
if err != nil { if err != nil {
return fmt.Errorf("Failed to Connect to KV store: %v", err) return fmt.Errorf("Failed to Connect to KV store: %v", err)

View file

@ -23,7 +23,7 @@ type Eureka struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Eureka) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ []types.Constraint) error { func (provider *Eureka) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ types.Constraints) error {
operation := func() error { operation := func() error {
configuration, err := provider.buildConfiguration() configuration, err := provider.buildConfiguration()

View file

@ -21,7 +21,7 @@ type File struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *File) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ []types.Constraint) error { func (provider *File) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
watcher, err := fsnotify.NewWatcher() watcher, err := fsnotify.NewWatcher()
if err != nil { if err != nil {
log.Error("Error creating file watcher", err) log.Error("Error creating file watcher", err)

View file

@ -42,7 +42,7 @@ func (provider *Kubernetes) newK8sClient() (k8s.Client, error) {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
k8sClient, err := provider.newK8sClient() k8sClient, err := provider.newK8sClient()
if err != nil { if err != nil {
return err return err

View file

@ -83,7 +83,7 @@ func (provider *Kv) watchKv(configurationChan chan<- types.ConfigMessage, prefix
return nil return nil
} }
func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
provider.Constraints = append(provider.Constraints, constraints...) provider.Constraints = append(provider.Constraints, constraints...)
operation := func() error { operation := func() error {
if _, err := provider.kvclient.Exists("qmslkjdfmqlskdjfmqlksjazçueznbvbwzlkajzebvkwjdcqmlsfj"); err != nil { if _, err := provider.kvclient.Exists("qmslkjdfmqlskdjfmqlksjazçueznbvbwzlkajzebvkwjdcqmlsfj"); err != nil {

View file

@ -408,7 +408,7 @@ func TestKVLoadConfig(t *testing.T) {
}, },
{ {
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot/weight", Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot/weight",
Value: []byte("1"), Value: []byte("0"),
}, },
}, },
}, },
@ -420,7 +420,7 @@ func TestKVLoadConfig(t *testing.T) {
Servers: map[string]types.Server{ Servers: map[string]types.Server{
"server.with.dot": { "server.with.dot": {
URL: "http://172.17.0.2:80", URL: "http://172.17.0.2:80",
Weight: 1, Weight: 0,
}, },
}, },
CircuitBreaker: nil, CircuitBreaker: nil,

View file

@ -4,7 +4,6 @@ import (
"errors" "errors"
"net" "net"
"net/url" "net/url"
"sort"
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
@ -53,7 +52,7 @@ type lightMarathonClient interface {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
provider.Constraints = append(provider.Constraints, constraints...) provider.Constraints = append(provider.Constraints, constraints...)
operation := func() error { operation := func() error {
config := marathon.NewDefaultConfig() config := marathon.NewDefaultConfig()
@ -226,10 +225,7 @@ func (provider *Marathon) taskFilter(task marathon.Task, applications *marathon.
log.Debugf("Filtering marathon task %s specifying both traefik.portIndex and traefik.port labels", task.AppID) log.Debugf("Filtering marathon task %s specifying both traefik.portIndex and traefik.port labels", task.AppID)
return false return false
} }
if portIndexLabel == "" && portValueLabel == "" && len(application.Ports) > 1 {
log.Debugf("Filtering marathon task %s with more than 1 port and no traefik.portIndex or traefik.port label", task.AppID)
return false
}
if portIndexLabel != "" { if portIndexLabel != "" {
index, err := strconv.Atoi((*application.Labels)["traefik.portIndex"]) index, err := strconv.Atoi((*application.Labels)["traefik.portIndex"])
if err != nil || index < 0 || index > len(application.Ports)-1 { if err != nil || index < 0 || index > len(application.Ports)-1 {
@ -429,7 +425,7 @@ func (provider *Marathon) getFrontendBackend(application marathon.Application) s
func (provider *Marathon) getSubDomain(name string) string { func (provider *Marathon) getSubDomain(name string) string {
if provider.GroupsAsSubDomains { if provider.GroupsAsSubDomains {
splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/") splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/")
sort.Sort(sort.Reverse(sort.StringSlice(splitedName))) reverseStringSlice(&splitedName)
reverseName := strings.Join(splitedName, ".") reverseName := strings.Join(splitedName, ".")
return reverseName return reverseName
} }

View file

@ -371,30 +371,30 @@ func TestMarathonTaskFilter(t *testing.T) {
}, },
{ {
task: marathon.Task{ task: marathon.Task{
AppID: "foo", AppID: "multiple-ports",
Ports: []int{80}, Ports: []int{80, 443},
}, },
applications: &marathon.Applications{ applications: &marathon.Applications{
Apps: []marathon.Application{ Apps: []marathon.Application{
{ {
ID: "foo", ID: "multiple-ports",
Ports: []int{80, 443}, Ports: []int{80, 443},
Labels: &map[string]string{}, Labels: &map[string]string{},
}, },
}, },
}, },
expected: false, expected: true,
exposedByDefault: true, exposedByDefault: true,
}, },
{ {
task: marathon.Task{ task: marathon.Task{
AppID: "foo", AppID: "disable",
Ports: []int{80}, Ports: []int{80},
}, },
applications: &marathon.Applications{ applications: &marathon.Applications{
Apps: []marathon.Application{ Apps: []marathon.Application{
{ {
ID: "foo", ID: "disable",
Ports: []int{80}, Ports: []int{80},
Labels: &map[string]string{ Labels: &map[string]string{
"traefik.enable": "false", "traefik.enable": "false",
@ -523,7 +523,7 @@ func TestMarathonTaskFilter(t *testing.T) {
}, },
{ {
task: marathon.Task{ task: marathon.Task{
AppID: "foo", AppID: "healthcheck-false",
Ports: []int{80}, Ports: []int{80},
HealthCheckResults: []*marathon.HealthCheckResult{ HealthCheckResults: []*marathon.HealthCheckResult{
{ {
@ -534,7 +534,7 @@ func TestMarathonTaskFilter(t *testing.T) {
applications: &marathon.Applications{ applications: &marathon.Applications{
Apps: []marathon.Application{ Apps: []marathon.Application{
{ {
ID: "foo", ID: "healthcheck-false",
Ports: []int{80}, Ports: []int{80},
Labels: &map[string]string{}, Labels: &map[string]string{},
HealthChecks: &[]marathon.HealthCheck{ HealthChecks: &[]marathon.HealthCheck{
@ -576,13 +576,13 @@ func TestMarathonTaskFilter(t *testing.T) {
}, },
{ {
task: marathon.Task{ task: marathon.Task{
AppID: "foo", AppID: "single-port",
Ports: []int{80}, Ports: []int{80},
}, },
applications: &marathon.Applications{ applications: &marathon.Applications{
Apps: []marathon.Application{ Apps: []marathon.Application{
{ {
ID: "foo", ID: "single-port",
Ports: []int{80}, Ports: []int{80},
Labels: &map[string]string{}, Labels: &map[string]string{},
}, },
@ -593,7 +593,7 @@ func TestMarathonTaskFilter(t *testing.T) {
}, },
{ {
task: marathon.Task{ task: marathon.Task{
AppID: "foo", AppID: "healthcheck-alive",
Ports: []int{80}, Ports: []int{80},
HealthCheckResults: []*marathon.HealthCheckResult{ HealthCheckResults: []*marathon.HealthCheckResult{
{ {
@ -604,7 +604,7 @@ func TestMarathonTaskFilter(t *testing.T) {
applications: &marathon.Applications{ applications: &marathon.Applications{
Apps: []marathon.Application{ Apps: []marathon.Application{
{ {
ID: "foo", ID: "healthcheck-alive",
Ports: []int{80}, Ports: []int{80},
Labels: &map[string]string{}, Labels: &map[string]string{},
HealthChecks: &[]marathon.HealthCheck{ HealthChecks: &[]marathon.HealthCheck{
@ -677,7 +677,7 @@ func TestMarathonTaskFilter(t *testing.T) {
for _, c := range cases { for _, c := range cases {
actual := provider.taskFilter(c.task, c.applications, c.exposedByDefault) actual := provider.taskFilter(c.task, c.applications, c.exposedByDefault)
if actual != c.expected { if actual != c.expected {
t.Fatalf("expected %v, got %v", c.expected, actual) t.Fatalf("App %s: expected %v, got %v", c.task.AppID, c.expected, actual)
} }
} }
} }
@ -740,7 +740,7 @@ func TestMarathonAppConstraints(t *testing.T) {
MarathonLBCompatibility: c.marathonLBCompatibility, MarathonLBCompatibility: c.marathonLBCompatibility,
} }
constraint, _ := types.NewConstraint("tag==valid") constraint, _ := types.NewConstraint("tag==valid")
provider.Constraints = []types.Constraint{*constraint} provider.Constraints = types.Constraints{constraint}
actual := provider.applicationFilter(c.application, c.filteredTasks) actual := provider.applicationFilter(c.application, c.filteredTasks)
if actual != c.expected { if actual != c.expected {
t.Fatalf("expected %v, got %v: %v", c.expected, actual, c.application) t.Fatalf("expected %v, got %v: %v", c.expected, actual, c.application)
@ -820,7 +820,7 @@ func TestMarathonTaskConstraints(t *testing.T) {
MarathonLBCompatibility: c.marathonLBCompatibility, MarathonLBCompatibility: c.marathonLBCompatibility,
} }
constraint, _ := types.NewConstraint("tag==valid") constraint, _ := types.NewConstraint("tag==valid")
provider.Constraints = []types.Constraint{*constraint} provider.Constraints = types.Constraints{constraint}
apps := new(marathon.Applications) apps := new(marathon.Applications)
apps.Apps = c.applications apps.Apps = c.applications
actual := provider.taskFilter(c.filteredTask, apps, true) actual := provider.taskFilter(c.filteredTask, apps, true)
@ -927,12 +927,12 @@ func TestMarathonGetPort(t *testing.T) {
{ {
applications: []marathon.Application{ applications: []marathon.Application{
{ {
ID: "test1", ID: "multiple-ports-take-first",
Labels: &map[string]string{}, Labels: &map[string]string{},
}, },
}, },
task: marathon.Task{ task: marathon.Task{
AppID: "test1", AppID: "multiple-ports-take-first",
Ports: []int{80, 443}, Ports: []int{80, 443},
}, },
expected: "80", expected: "80",
@ -1280,3 +1280,33 @@ func TestMarathonGetBackend(t *testing.T) {
} }
} }
} }
func TestMarathonGetSubDomain(t *testing.T) {
providerGroups := &Marathon{GroupsAsSubDomains: true}
providerNoGroups := &Marathon{GroupsAsSubDomains: false}
apps := []struct {
path string
expected string
provider *Marathon
}{
{"/test", "test", providerNoGroups},
{"/test", "test", providerGroups},
{"/a/b/c/d", "d.c.b.a", providerGroups},
{"/b/a/d/c", "c.d.a.b", providerGroups},
{"/d/c/b/a", "a.b.c.d", providerGroups},
{"/c/d/a/b", "b.a.d.c", providerGroups},
{"/a/b/c/d", "a-b-c-d", providerNoGroups},
{"/b/a/d/c", "b-a-d-c", providerNoGroups},
{"/d/c/b/a", "d-c-b-a", providerNoGroups},
{"/c/d/a/b", "c-d-a-b", providerNoGroups},
}
for _, a := range apps {
actual := a.provider.getSubDomain(a.path)
if actual != a.expected {
t.Errorf("expected %q, got %q", a.expected, actual)
}
}
}

View file

@ -7,6 +7,8 @@ import (
"text/template" "text/template"
"fmt" "fmt"
"time"
"github.com/BurntSushi/ty/fun" "github.com/BurntSushi/ty/fun"
"github.com/cenk/backoff" "github.com/cenk/backoff"
"github.com/containous/traefik/job" "github.com/containous/traefik/job"
@ -20,8 +22,6 @@ import (
"github.com/mesosphere/mesos-dns/records" "github.com/mesosphere/mesos-dns/records"
"github.com/mesosphere/mesos-dns/records/state" "github.com/mesosphere/mesos-dns/records/state"
"github.com/mesosphere/mesos-dns/util" "github.com/mesosphere/mesos-dns/util"
"sort"
"time"
) )
var _ Provider = (*Mesos)(nil) var _ Provider = (*Mesos)(nil)
@ -42,7 +42,7 @@ type Mesos struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Mesos) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Mesos) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
operation := func() error { operation := func() error {
// initialize logging // initialize logging
@ -212,10 +212,6 @@ func mesosTaskFilter(task state.Task, exposedByDefaultFlag bool) bool {
log.Debugf("Filtering mesos task %s specifying both traefik.portIndex and traefik.port labels", task.Name) log.Debugf("Filtering mesos task %s specifying both traefik.portIndex and traefik.port labels", task.Name)
return false return false
} }
if portIndexLabel == "" && portValueLabel == "" && len(task.DiscoveryInfo.Ports.DiscoveryPorts) > 1 {
log.Debugf("Filtering mesos task %s with more than 1 port and no traefik.portIndex or traefik.port label", task.Name)
return false
}
if portIndexLabel != "" { if portIndexLabel != "" {
index, err := strconv.Atoi(labels(task, "traefik.portIndex")) index, err := strconv.Atoi(labels(task, "traefik.portIndex"))
if err != nil || index < 0 || index > len(task.DiscoveryInfo.Ports.DiscoveryPorts)-1 { if err != nil || index < 0 || index > len(task.DiscoveryInfo.Ports.DiscoveryPorts)-1 {
@ -439,7 +435,7 @@ func Ignore(f ErrorFunction) {
func (provider *Mesos) getSubDomain(name string) string { func (provider *Mesos) getSubDomain(name string) string {
if provider.GroupsAsSubDomains { if provider.GroupsAsSubDomains {
splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/") splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/")
sort.Sort(sort.Reverse(sort.StringSlice(splitedName))) reverseStringSlice(&splitedName)
reverseName := strings.Join(splitedName, ".") reverseName := strings.Join(splitedName, ".")
return reverseName return reverseName
} }

View file

@ -1,11 +1,12 @@
package provider package provider
import ( import (
"reflect"
"testing"
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"github.com/mesosphere/mesos-dns/records/state" "github.com/mesosphere/mesos-dns/records/state"
"reflect"
"testing"
) )
func TestMesosTaskFilter(t *testing.T) { func TestMesosTaskFilter(t *testing.T) {
@ -95,7 +96,7 @@ func TestMesosTaskFilter(t *testing.T) {
setLabels("traefik.enable", "true"), setLabels("traefik.enable", "true"),
discovery(setDiscoveryPorts("TCP", 80, "WEB HTTP", "TCP", 443, "WEB HTTPS")), discovery(setDiscoveryPorts("TCP", 80, "WEB HTTP", "TCP", 443, "WEB HTTPS")),
), ),
expected: false, // more than 1 discovery port but no traefik.port* label expected: true, // Default to first index
exposedByDefault: true, exposedByDefault: true,
}, },
{ {
@ -244,6 +245,36 @@ func TestMesosLoadConfig(t *testing.T) {
} }
} }
func TestMesosGetSubDomain(t *testing.T) {
providerGroups := &Mesos{GroupsAsSubDomains: true}
providerNoGroups := &Mesos{GroupsAsSubDomains: false}
apps := []struct {
path string
expected string
provider *Mesos
}{
{"/test", "test", providerNoGroups},
{"/test", "test", providerGroups},
{"/a/b/c/d", "d.c.b.a", providerGroups},
{"/b/a/d/c", "c.d.a.b", providerGroups},
{"/d/c/b/a", "a.b.c.d", providerGroups},
{"/c/d/a/b", "b.a.d.c", providerGroups},
{"/a/b/c/d", "a-b-c-d", providerNoGroups},
{"/b/a/d/c", "b-a-d-c", providerNoGroups},
{"/d/c/b/a", "d-c-b-a", providerNoGroups},
{"/c/d/a/b", "c-d-a-b", providerNoGroups},
}
for _, a := range apps {
actual := a.provider.getSubDomain(a.path)
if actual != a.expected {
t.Errorf("expected %q, got %q", a.expected, actual)
}
}
}
// test helpers // test helpers
type ( type (

View file

@ -23,7 +23,7 @@ import (
type Provider interface { type Provider interface {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error
} }
// BaseProvider should be inherited by providers // BaseProvider should be inherited by providers
@ -44,7 +44,7 @@ func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint)
for _, constraint := range p.Constraints { for _, constraint := range p.Constraints {
// xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint // xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint
if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch { if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch {
return false, &constraint return false, constraint
} }
} }
@ -101,6 +101,12 @@ func normalize(name string) string {
return strings.Join(strings.FieldsFunc(name, fargs), "-") return strings.Join(strings.FieldsFunc(name, fargs), "-")
} }
func reverseStringSlice(slice *[]string) {
for i, j := 0, len(*slice)-1; i < j; i, j = i+1, j-1 {
(*slice)[i], (*slice)[j] = (*slice)[j], (*slice)[i]
}
}
// ClientTLS holds TLS specific configurations as client // ClientTLS holds TLS specific configurations as client
// CA, Cert and Key can be either path or file contents // CA, Cert and Key can be either path or file contents
type ClientTLS struct { type ClientTLS struct {

View file

@ -230,13 +230,13 @@ func TestNilClientTLS(t *testing.T) {
func TestMatchingConstraints(t *testing.T) { func TestMatchingConstraints(t *testing.T) {
cases := []struct { cases := []struct {
constraints []types.Constraint constraints types.Constraints
tags []string tags []string
expected bool expected bool
}{ }{
// simple test: must match // simple test: must match
{ {
constraints: []types.Constraint{ constraints: types.Constraints{
{ {
Key: "tag", Key: "tag",
MustMatch: true, MustMatch: true,
@ -250,7 +250,7 @@ func TestMatchingConstraints(t *testing.T) {
}, },
// simple test: must match but does not match // simple test: must match but does not match
{ {
constraints: []types.Constraint{ constraints: types.Constraints{
{ {
Key: "tag", Key: "tag",
MustMatch: true, MustMatch: true,
@ -264,7 +264,7 @@ func TestMatchingConstraints(t *testing.T) {
}, },
// simple test: must not match // simple test: must not match
{ {
constraints: []types.Constraint{ constraints: types.Constraints{
{ {
Key: "tag", Key: "tag",
MustMatch: false, MustMatch: false,
@ -278,7 +278,7 @@ func TestMatchingConstraints(t *testing.T) {
}, },
// complex test: globbing // complex test: globbing
{ {
constraints: []types.Constraint{ constraints: types.Constraints{
{ {
Key: "tag", Key: "tag",
MustMatch: true, MustMatch: true,
@ -292,7 +292,7 @@ func TestMatchingConstraints(t *testing.T) {
}, },
// complex test: multiple constraints // complex test: multiple constraints
{ {
constraints: []types.Constraint{ constraints: types.Constraints{
{ {
Key: "tag", Key: "tag",
MustMatch: true, MustMatch: true,

View file

@ -17,7 +17,7 @@ type Zookepper struct {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Zookepper) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { func (provider *Zookepper) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
store, err := provider.CreateStore() store, err := provider.CreateStore()
if err != nil { if err != nil {
return fmt.Errorf("Failed to Connect to KV store: %v", err) return fmt.Errorf("Failed to Connect to KV store: %v", err)

View file

@ -27,7 +27,7 @@ OS_ARCH_ARG=(386 amd64)
for OS in ${OS_PLATFORM_ARG[@]}; do for OS in ${OS_PLATFORM_ARG[@]}; do
for ARCH in ${OS_ARCH_ARG[@]}; do for ARCH in ${OS_ARCH_ARG[@]}; do
echo "Building binary for $OS/$ARCH..." echo "Building binary for $OS/$ARCH..."
GOARCH=$ARCH GOOS=$OS CGO_ENABLED=0 go build -ldflags "-s -w -X main.Version=$VERSION -X main.Codename=$CODENAME -X main.BuildDate=$DATE" -o "dist/traefik_$OS-$ARCH" . GOARCH=$ARCH GOOS=$OS CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/containous/traefik/version.Version=$VERSION -X github.com/containous/traefik/version.Codename=$CODENAME -X github.com/containous/traefik/version.BuildDate=$DATE" -o "dist/traefik_$OS-$ARCH" .
done done
done done
@ -38,6 +38,6 @@ OS_ARCH_ARG=(arm arm64)
for OS in ${OS_PLATFORM_ARG[@]}; do for OS in ${OS_PLATFORM_ARG[@]}; do
for ARCH in ${OS_ARCH_ARG[@]}; do for ARCH in ${OS_ARCH_ARG[@]}; do
echo "Building binary for $OS/$ARCH..." echo "Building binary for $OS/$ARCH..."
GOARCH=$ARCH GOOS=$OS CGO_ENABLED=0 go build -ldflags "-s -w -X main.Version=$VERSION -X main.Codename=$CODENAME -X main.BuildDate=$DATE" -o "dist/traefik_$OS-$ARCH" . GOARCH=$ARCH GOOS=$OS CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/containous/traefik/version.Version=$VERSION -X github.com/containous/traefik/version.Codename=$CODENAME -X github.com/containous/traefik/version.BuildDate=$DATE" -o "dist/traefik_$OS-$ARCH" .
done done
done done

View file

@ -90,7 +90,7 @@ func NewServer(globalConfiguration GlobalConfiguration) *Server {
return server return server
} }
// Start starts the server and blocks until server is shutted down. // Start starts the server.
func (server *Server) Start() { func (server *Server) Start() {
server.startHTTPServers() server.startHTTPServers()
server.startLeadership() server.startLeadership()
@ -103,6 +103,10 @@ func (server *Server) Start() {
server.configureProviders() server.configureProviders()
server.startProviders() server.startProviders()
go server.listenSignals() go server.listenSignals()
}
// Wait blocks until server is shutted down.
func (server *Server) Wait() {
<-server.stopChan <-server.stopChan
} }
@ -213,11 +217,11 @@ func (server *Server) listenProviders(stop chan bool) {
lastConfigs.Set(configMsg.ProviderName, &configMsg) lastConfigs.Set(configMsg.ProviderName, &configMsg)
lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time) lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time)
if time.Now().After(lastReceivedConfigurationValue.Add(time.Duration(server.globalConfiguration.ProvidersThrottleDuration))) { if time.Now().After(lastReceivedConfigurationValue.Add(time.Duration(server.globalConfiguration.ProvidersThrottleDuration))) {
log.Debugf("Last %s config received more than %s, OK", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration) log.Debugf("Last %s config received more than %s, OK", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration.String())
// last config received more than n s ago // last config received more than n s ago
server.configurationValidatedChan <- configMsg server.configurationValidatedChan <- configMsg
} else { } else {
log.Debugf("Last %s config received less than %s, waiting...", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration) log.Debugf("Last %s config received less than %s, waiting...", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration.String())
safe.Go(func() { safe.Go(func() {
<-time.After(server.globalConfiguration.ProvidersThrottleDuration) <-time.After(server.globalConfiguration.ProvidersThrottleDuration)
lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time) lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time)
@ -387,6 +391,9 @@ func (server *Server) createTLSConfig(entryPointName string, tlsOption *TLS, rou
return nil, err return nil, err
} }
// ensure http2 enabled
config.NextProtos = []string{"h2", "http/1.1"}
if len(tlsOption.ClientCAFiles) > 0 { if len(tlsOption.ClientCAFiles) > 0 {
pool := x509.NewCertPool() pool := x509.NewCertPool()
for _, caFile := range tlsOption.ClientCAFiles { for _, caFile := range tlsOption.ClientCAFiles {

View file

@ -3,7 +3,7 @@
{{if ne (getAttribute "enable" $node.Service.Tags "true") "false"}} {{if ne (getAttribute "enable" $node.Service.Tags "true") "false"}}
[backends."backend-{{getBackend $node}}".servers."{{getBackendName $node $index}}"] [backends."backend-{{getBackend $node}}".servers."{{getBackendName $node $index}}"]
url = "{{getAttribute "protocol" $node.Service.Tags "http"}}://{{getBackendAddress $node}}:{{$node.Service.Port}}" url = "{{getAttribute "protocol" $node.Service.Tags "http"}}://{{getBackendAddress $node}}:{{$node.Service.Port}}"
{{$weight := getAttribute "backend.weight" $node.Service.Tags ""}} {{$weight := getAttribute "backend.weight" $node.Service.Tags "0"}}
{{with $weight}} {{with $weight}}
weight = {{$weight}} weight = {{$weight}}
{{end}} {{end}}

View file

@ -32,7 +32,7 @@
{{range $servers}} {{range $servers}}
[backends."{{Last $backend}}".servers."{{Last .}}"] [backends."{{Last $backend}}".servers."{{Last .}}"]
url = "{{Get "" . "/url"}}" url = "{{Get "" . "/url"}}"
weight = {{Get "" . "/weight"}} weight = {{Get "0" . "/weight"}}
{{end}} {{end}}
{{end}} {{end}}

View file

@ -11,6 +11,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"text/template" "text/template"
"time"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/containous/flaeg" "github.com/containous/flaeg"
@ -20,8 +21,10 @@ import (
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares" "github.com/containous/traefik/middlewares"
"github.com/containous/traefik/provider/k8s" "github.com/containous/traefik/provider/k8s"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"github.com/containous/traefik/version" "github.com/containous/traefik/version"
"github.com/coreos/go-systemd/daemon"
"github.com/docker/libkv/store" "github.com/docker/libkv/store"
"github.com/satori/go.uuid" "github.com/satori/go.uuid"
) )
@ -261,6 +264,20 @@ func run(traefikConfiguration *TraefikConfiguration) {
} }
jsonConf, _ := json.Marshal(globalConfiguration) jsonConf, _ := json.Marshal(globalConfiguration)
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate) log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
if globalConfiguration.CheckNewVersion {
ticker := time.NewTicker(24 * time.Hour)
safe.Go(func() {
version.CheckNewVersion()
for {
select {
case <-ticker.C:
version.CheckNewVersion()
}
}
})
}
if len(traefikConfiguration.ConfigFile) != 0 { if len(traefikConfiguration.ConfigFile) != 0 {
log.Infof("Using TOML configuration file %s", traefikConfiguration.ConfigFile) log.Infof("Using TOML configuration file %s", traefikConfiguration.ConfigFile)
} }
@ -268,6 +285,11 @@ func run(traefikConfiguration *TraefikConfiguration) {
server := NewServer(globalConfiguration) server := NewServer(globalConfiguration)
server.Start() server.Start()
defer server.Close() defer server.Close()
sent, err := daemon.SdNotify("READY=1")
if !sent && err != nil {
log.Error("Fail to notify", err)
}
server.Wait()
log.Info("Shutting down") log.Info("Shutting down")
} }

View file

@ -10,6 +10,20 @@
# #
# graceTimeOut = 10 # graceTimeOut = 10
# Enable debug mode
#
# Optional
# Default: false
#
# debug = true
# Periodically check if a new version has been released
#
# Optional
# Default: true
#
# checkNewVersion = false
# Traefik logs file # Traefik logs file
# If not defined, logs to stdout # If not defined, logs to stdout
# #
@ -30,14 +44,14 @@
# #
# logLevel = "ERROR" # logLevel = "ERROR"
# Backends throttle duration: minimum duration between 2 events from providers # Backends throttle duration: minimum duration in seconds between 2 events from providers
# before applying a new configuration. It avoids unnecessary reloads if multiples events # before applying a new configuration. It avoids unnecessary reloads if multiples events
# are sent in a short amount of time. # are sent in a short amount of time.
# #
# Optional # Optional
# Default: "2s" # Default: "2"
# #
# ProvidersThrottleDuration = "5s" # ProvidersThrottleDuration = "5"
# If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. # If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used.
# If you encounter 'too many open files' errors, you can either change this value, or change `ulimit` value. # If you encounter 'too many open files' errors, you can either change this value, or change `ulimit` value.
@ -284,7 +298,7 @@
# To enable digest auth on the webui # To enable digest auth on the webui
# with 2 user/realm/pass: test:traefik:test and test2:traefik:test2 # with 2 user/realm/pass: test:traefik:test and test2:traefik:test2
# You can use htdigest to generate those ones # You can use htdigest to generate those ones
# [web.auth.basic] # [web.auth.digest]
# users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"] # users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]

View file

@ -1,6 +1,7 @@
package types package types
import ( import (
"encoding"
"errors" "errors"
"fmt" "fmt"
"github.com/docker/libkv/store" "github.com/docker/libkv/store"
@ -141,12 +142,26 @@ func (c *Constraint) String() string {
return c.Key + "!=" + c.Regex return c.Key + "!=" + c.Regex
} }
var _ encoding.TextUnmarshaler = (*Constraint)(nil)
// UnmarshalText define how unmarshal in TOML parsing // UnmarshalText define how unmarshal in TOML parsing
func (c *Constraint) UnmarshalText(text []byte) error { func (c *Constraint) UnmarshalText(text []byte) error {
constraint, err := NewConstraint(string(text)) constraint, err := NewConstraint(string(text))
*c = *constraint if err != nil {
return err return err
} }
c.Key = constraint.Key
c.MustMatch = constraint.MustMatch
c.Regex = constraint.Regex
return nil
}
var _ encoding.TextMarshaler = (*Constraint)(nil)
// MarshalText encodes the receiver into UTF-8-encoded text and returns the result.
func (c *Constraint) MarshalText() (text []byte, err error) {
return []byte(c.String()), nil
}
// MatchConstraintWithAtLeastOneTag tests a constraint for one single service // MatchConstraintWithAtLeastOneTag tests a constraint for one single service
func (c *Constraint) MatchConstraintWithAtLeastOneTag(tags []string) bool { func (c *Constraint) MatchConstraintWithAtLeastOneTag(tags []string) bool {
@ -169,16 +184,16 @@ func (cs *Constraints) Set(str string) error {
if err != nil { if err != nil {
return err return err
} }
*cs = append(*cs, *constraint) *cs = append(*cs, constraint)
} }
return nil return nil
} }
// Constraints holds a Constraint parser // Constraints holds a Constraint parser
type Constraints []Constraint type Constraints []*Constraint
//Get []*Constraint //Get []*Constraint
func (cs *Constraints) Get() interface{} { return []Constraint(*cs) } func (cs *Constraints) Get() interface{} { return []*Constraint(*cs) }
//String returns []*Constraint in string //String returns []*Constraint in string
func (cs *Constraints) String() string { return fmt.Sprintf("%+v", *cs) } func (cs *Constraints) String() string { return fmt.Sprintf("%+v", *cs) }
@ -216,12 +231,12 @@ type Users []string
// Basic HTTP basic authentication // Basic HTTP basic authentication
type Basic struct { type Basic struct {
Users Users `mapstructure:","`
} }
// Digest HTTP authentication // Digest HTTP authentication
type Digest struct { type Digest struct {
Users Users `mapstructure:","`
} }
// CanonicalDomain returns a lower case domain with trim space // CanonicalDomain returns a lower case domain with trim space

View file

@ -1,5 +1,12 @@
package version package version
import (
"github.com/containous/traefik/log"
"github.com/google/go-github/github"
goversion "github.com/hashicorp/go-version"
"net/url"
)
var ( var (
// Version holds the current version of traefik. // Version holds the current version of traefik.
Version = "dev" Version = "dev"
@ -8,3 +15,50 @@ var (
// BuildDate holds the build date of traefik. // BuildDate holds the build date of traefik.
BuildDate = "I don't remember exactly" BuildDate = "I don't remember exactly"
) )
// CheckNewVersion checks if a new version is available
func CheckNewVersion() {
if Version == "dev" {
return
}
client := github.NewClient(nil)
updateURL, err := url.Parse("https://update.traefik.io")
if err != nil {
log.Warnf("Error checking new version: %s", err)
return
}
client.BaseURL = updateURL
releases, resp, err := client.Repositories.ListReleases("containous", "traefik", nil)
if err != nil {
log.Warnf("Error checking new version: %s", err)
return
}
if resp.StatusCode != 200 {
log.Warnf("Error checking new version: status=%s", resp.Status)
return
}
currentVersion, err := goversion.NewVersion(Version)
if err != nil {
log.Warnf("Error checking new version: %s", err)
return
}
for _, release := range releases {
releaseVersion, err := goversion.NewVersion(*release.TagName)
if err != nil {
log.Warnf("Error checking new version: %s", err)
return
}
if len(currentVersion.Prerelease()) == 0 && len(releaseVersion.Prerelease()) > 0 {
continue
}
if releaseVersion.GreaterThan(currentVersion) {
log.Warnf("A new release has been found: %s. Please consider updating.", releaseVersion.String())
return
}
}
}

2
web.go
View file

@ -54,7 +54,7 @@ func goroutines() interface{} {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *WebProvider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ []types.Constraint) error { func (provider *WebProvider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ types.Constraints) error {
systemRouter := mux.NewRouter() systemRouter := mux.NewRouter()

View file

@ -21,7 +21,8 @@
"angular-ui-bootstrap": "^2.0.0", "angular-ui-bootstrap": "^2.0.0",
"angular-ui-router": "^0.3.1", "angular-ui-router": "^0.3.1",
"bootstrap": "^3.3.6", "bootstrap": "^3.3.6",
"moment": "^2.14.1" "moment": "^2.14.1",
"nvd3": "^1.8.4"
}, },
"devDependencies": { "devDependencies": {
"angular-mocks": "^1.4.2", "angular-mocks": "^1.4.2",
@ -80,11 +81,6 @@
"test": "gulp test", "test": "gulp test",
"test:auto": "gulp test:auto" "test:auto": "gulp test:auto"
}, },
"overrides": {
"angular-nvd3": {
"main": "dist/angular-nvd3.js"
}
},
"eslintConfig": { "eslintConfig": {
"globals": { "globals": {
"expect": true "expect": true