1
0
mirror of https://github.com/containous/traefik.git synced 2025-09-10 21:44:31 +03:00

Compare commits

..

358 Commits
v1.2.2 ... v1.3

Author SHA1 Message Date
mmatur
3dfbdd8029 fix: docs build trusted host 2024-05-16 21:09:16 +02:00
mmatur
0a98005c1f fix: docs build alpine version 2024-05-16 16:26:39 +02:00
mmatur
b5b8ef2e34 feat: add dockerfile for documentation 2021-10-05 10:27:18 +02:00
Fernandez Ludovic
1476eba60a doc: fix version in requirements.txt 2018-08-06 17:07:32 +02:00
Michael
06837e2508 [doc] fix version in requirements.txt
To be able to generate versionned documentation
2018-01-19 15:47:57 +01:00
Ludovic Fernandez
1b42030d58 Force GOARM to v6. 2017-09-08 14:52:03 +02:00
Ludovic Fernandez
d7d7eb2b83 Prepare release v1.3.8 2017-09-07 22:04:03 +02:00
Ludovic Fernandez
47bc2aaf62 Fix: compress and oxy 2017-09-07 17:38:05 +02:00
Ludovic Fernandez
7b0cef0fac Prepare release v1.3.7 2017-08-25 17:08:02 +02:00
Ludovic Fernandez
919295cffc Only forward X-Fowarded-Port. 2017-08-25 12:14:03 +02:00
Ludovic Fernandez
78544f7fa2 Prepare release v1.3.6 2017-08-22 09:52:02 +02:00
Ludovic Fernandez
40e18db838 Websocket parameters and protocol. 2017-08-20 19:02:02 +02:00
Ludovic Fernandez
413ed62933 Prepare release v1.3.5 2017-08-01 17:43:37 +02:00
SALLEYRON Julien
1b4dc3783c Oxy with fixes on websocket + integration tests 2017-08-01 15:24:08 +02:00
Julien Salleyron
1db9482a8e Prepare release v1.3.4 2017-07-27 17:24:19 +02:00
Julien Salleyron
888e6dcbc8 Oxy with gorilla for websocket(+integration tests) 2017-07-27 15:43:12 +02:00
dedalusj
a09a8b1235 Fix replace path rule
* Fix replace path rule
* test: add RequestURI tests.
2017-07-19 10:27:52 +02:00
Fernandez Ludovic
36ee69609e fix: double compression. 2017-07-18 11:27:24 +02:00
Fernandez Ludovic
98b52d1f54 Prepare release v1.3.3 2017-07-06 17:53:35 +02:00
Timo Reimann
4892b2b0da [kubernetes] Undo the Secrets controller sync wait.
When Secrets permissions have not been granted (which is likely to be
the case for users not needing the basic auth feature), the watch on the
Secrets API will never yield a response, thereby causing the controller
to never sync successfully, and in turn causing the check for all
controller synchronizations to fail consistently. Thus, no event will
ever be handled.
2017-07-06 17:12:25 +02:00
Timo Reimann
91ce78da46 [k8s] Tell glog to log everything into STDERR.
Logging errors into a file inside a minimalistic container might not be
possible, and glog bails out with an exit code > 0 if it fails.
2017-07-04 17:11:50 +02:00
Fernandez Ludovic
f06e256934 Prepare release v1.3.2 2017-06-29 17:40:11 +02:00
Fernandez Ludovic
4699d6be18 Fix proxying of unannounced trailers 2017-06-29 17:03:29 +02:00
Timo Reimann
6473002021 Continue Ingress processing on auth retrieval failure. 2017-06-29 16:13:53 +02:00
Timo Reimann
4d89ff7e18 Improve basic auth handling.
- Enrich logging.
- Move error closer to producer.
2017-06-29 16:13:53 +02:00
Timo Reimann
c5c63071ca Wait for secret controller to finish synchronizing.
Prevents a race on closing the events channel, possibly leading to a
double-close.
2017-06-29 16:13:53 +02:00
Timo Reimann
9fbe21c534 Upgrade go-marathon to dd6cbd4.
Fixes a problem with UnreachableStrategy being available now in two
type-incompatible formats (object and string).

We also upgrade the transitive dependency
github.com/donovanhide/eventsource.
2017-06-29 09:59:20 +02:00
Fernandez Ludovic
7a34303593 chore: Bump Docker version to 17.03 2017-06-27 23:22:43 +02:00
Fernandez Ludovic
fdb24c64e4 chore(semaphoreci): update Docker version. 2017-06-27 14:05:44 +02:00
nmengin
631079a12f feature: Add provided certificates check before to generate ACME certificate when OnHostRule is activated
- ADD TI to check the new behaviour with onHostRule and provided certificates
- ADD TU on the getProvidedCertificate method
2017-06-26 18:32:55 +02:00
Fernandez Ludovic
f99f3b987e fix: websocket when the connection upgrade failed. 2017-06-26 18:00:03 +02:00
Fernandez Ludovic
fe4d0e95b3 Prepare release v1.3.1 2017-06-16 12:53:26 +02:00
Fernandez Ludovic
0fb63f4488 fix(webui): don't fail when backend or frontend are empty. 2017-06-16 10:38:58 +02:00
Fernandez Ludovic
d87c4d89e9 fix: Double GZIP. 2017-06-14 21:13:38 +02:00
Fernandez Ludovic
ccc429e36c refactor(eureka): Use Traefik Logger. 2017-06-14 19:49:45 +02:00
Fernandez Ludovic
0d25ba3cbc refactor: Add explicit error message. 2017-06-14 19:49:45 +02:00
Kekoa Vincent
ac5ab13a4c Fix errors caused by incorrect type being sent for the Kubernetes Secret watcher #1596
This was likely just a copy-paste issue, the bug should be benign because the secret is cast to the correct type later, but the additional logging is a major annoyance, and is happening even if basic auth is not in use with Kubernetes.
2017-06-02 19:20:47 +02:00
Maxime Guyot
1db22a6e63 Fix capitalization of PathPrefixStrip in kubernetes doc 2017-06-01 20:40:28 +02:00
Fernandez Ludovic
e1e07f7750 Prepare release v1.3.0 2017-05-31 10:11:16 -07:00
Fernandez Ludovic
4c4eba4b56 doc(changelog): replace GitHub API URL by HTML URL. 2017-05-30 19:48:01 +02:00
Fernandez Ludovic
dbfd2663c2 Prepare release v1.3.0-rc3 2017-05-24 15:32:29 +02:00
Fernandez Ludovic
5b896bb46c fix: Empty Rancher launch config. 2017-05-24 11:20:30 +02:00
Josh Toft
bc0121808a Fix behavior for PathPrefixStrip
When pushing data to downstream proxies; malformed requests were being
sent.

The corrected behavior is as follows:

| Route Stripped    |     URL                |  Passed to Backend |
| ----------------- | ---------------------- | ------------------ |
| /                 |     /                  |  /                 |

| Route Stripped    |     URL                |  Passed to Backend |
| ----------------- | ---------------------- | ------------------ |
| /stat             |     /stat              |  /                 |
| /stat             |     /stat/             |  /                 |
| /stat             |     /status            |  /status           |
| /stat             |     /stat/us           |  /us               |

| Route Stripped    |     URL                |  Passed to Backend |
| ----------------- | ---------------------- | ------------------ |
| /stat/            |     /stat              |  /stat             |
| /stat/            |     /stat/             |  /                 |
| /stat/            |     /status            |  /status           |
| /stat/            |     /stat/us           |  /us               |

Prior, we could strip the prefixing `/`, and we'd also ignore the case
where you want to serve something like `/api` as both the index and as a
subpath.

Additionally, this should resolve a myriad of issues relating to
kubernetes ingress `PathPrefixStrip`.
2017-05-24 10:50:12 +02:00
Timo Reimann
4293446111 Install github.com/stretchr/testify/require. 2017-05-24 00:51:48 +02:00
Timo Reimann
9967494996 [k8s] Ignore Ingresses with empty Endpoint subsets.
We previously fell back to using ClusterIPs. However, the approach can
lead to all kinds of problems since Ingresses rely on being able to talk
to Endpoints directly. For instance, it can break stickiness and
retries.
2017-05-23 21:15:06 +02:00
Timo Reimann
b392023c37 Add additional tests for PathStrip{Prefix}. 2017-05-23 17:31:34 +02:00
Timo Reimann
f7d9dfafd0 [k8s] Remove rule type path list.
Instead of doing sanity checks in the Kubernetes provider, we just
accept any non-empty value from the annotation and rely on the server
part to filter out unknown rules.

This allows us to automatically stay in sync with the currently
supported Path matchers/modifiers.
2017-05-23 17:31:34 +02:00
Timo Reimann
219a6372b0 Upgrade go-marathon to 15ea23e.
Our vendored copy contains a bug that causes unavailable Marathon nodes
to never be marked as available again due to a misconstruction in the
URL to the Marathon health check / ping endpoint used by go-marathon
internally.

A fix[1] has been published.

[1]https://github.com/gambol99/go-marathon/pull/283
2017-05-22 20:52:24 +02:00
Fernandez Ludovic
2e762e76f3 doc: update change log. 2017-05-22 10:26:05 +02:00
tanyadegurechaff
987ae92f53 Create log folder if not present 2017-05-19 15:49:02 +02:00
Ed Robinson
c1220b8765 Re Orginise k8s docs to make 1.6 usage easier
* Adds some raw.githubusercontent.com links to the kubectl examples to
make following along at home simpler.
* Dedupe the config for rbac so it can just be ommited if not needed.
2017-05-17 15:58:54 +02:00
Emile Vauge
bc6f764a87 Merge pull request #1578 from Stibbons/marathon_doc
Add Marathon guide.
2017-05-17 15:21:09 +02:00
Gaetan Semet
0b414ed482 Add Marathon guide
Copy/pasted from very comprehensive slack response from @ttr
https://traefik.slack.com/archives/C0CDT22PJ/p1494347929571784?thread_ts=1494339388.375916&cid=C0CDT22PJ

Signed-off-by: Gaetan Semet <gaetan@xeberon.net>
2017-05-17 14:59:28 +02:00
Emile Vauge
f521e72f15 Merge pull request #1612 from containous/fix-deploy
Fix deploy script, removes Docker version check
2017-05-16 17:53:47 +02:00
Emile Vauge
88ea0a037b Fix deploy script, removes Docker version check 2017-05-16 17:24:08 +02:00
Emile Vauge
c963cee3c8 Merge pull request #1606 from containous/prepare-release-v1.3.0-rc2
Prepare release v1.3.0-rc2
2017-05-16 16:15:05 +02:00
Emile Vauge
0be353d435 Merge pull request #1610 from ldez/beta-cluster
doc: Traefik cluster in beta.
2017-05-16 15:50:03 +02:00
Emile Vauge
6afff2d403 Merge pull request #1610 from ldez/beta-cluster
doc: Traefik cluster in beta.
2017-05-16 15:47:11 +02:00
Fernandez Ludovic
12fa144f2f doc: Traefik cluster in beta. 2017-05-16 15:28:18 +02:00
Emile Vauge
ac0e48b48c Merge pull request #1608 from ldez/feat-semaphoreci
SemaphoreCI on 1.3 branch
2017-05-16 15:08:39 +02:00
Attilio Borello
64aa37858b added retry function to validate script 2017-05-16 14:33:06 +02:00
Attilio Borello
5348d4dccd added retry function to tests script 2017-05-16 14:33:06 +02:00
Attilio Borello
c3c599241f removed unit and integration tests from travis 2017-05-16 14:33:06 +02:00
Attilio Borello
c19432f95c clean up apt-cache in webui/Dockerfile 2017-05-16 14:33:06 +02:00
Attilio Borello
bdf4f48d78 replaced docker images with alpine if available (nginx, rabbitmq) 2017-05-16 14:33:06 +02:00
Attilio Borello
21aa0ea2da added DOCKER_VERSION variable 2017-05-16 14:33:06 +02:00
Timo Reimann
f8e7b5595b Merge pull request #1585 from timoreimann/1-3-maintain-sticky-flag-on-lb-method-validation-failure
Maintain sticky flag on LB method validation failure.
2017-05-16 00:41:15 +02:00
Timo Reimann
f9839f7b1d Turn configureBackends into method. 2017-05-16 00:06:42 +02:00
Timo Reimann
2c45428c8a Maintain sticky flag on LB method validation failure.
We previously did not copy the sticky flag if the load-balancer
method validation failed, causing enabled stickiness to be dropped in
case of a validation error (which, technically, for us is the same as a
load-balancer configuration without an explicitly set method). This
change fixes that.

A few refactorings and improvements along the way:

- Move the frontend and backend configuration steps into separate
  methods/functions for better testability.
- Include the invalid method name in the error value and avoid log
  duplication.
- Add tests for the backend configuration part.
2017-05-16 00:06:42 +02:00
Emile Vauge
30aa5a82b3 Merge pull request #1577 from aantono/Issue1569
Fixed ReplacePath rule executing out of order, when combined with PathPrefixStrip
2017-05-15 23:21:53 +02:00
Alex Antonov
3f68e382fd Fixed ReplacePath rule executing out of order, when combined with PathPrefixStrip #1569 2017-05-15 10:08:18 -05:00
Emile Vauge
9e57a283d7 Merge pull request #1601 from containous/fix-fatal-auth
Fix empty basic auth
2017-05-15 17:00:52 +02:00
Emile Vauge
eaedc1b924 Fix empty basic auth
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-15 16:03:46 +02:00
Emile Vauge
e3ab4e4d63 Merge pull request #1598 from containous/fix-stats-hijack
Fix stats hijack
2017-05-15 15:04:23 +02:00
Emile Vauge
48a91d05b5 Add Recover tests 2017-05-15 09:17:33 +02:00
Emile Vauge
111251da05 Adds Panic Recover middleware
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-15 09:17:33 +02:00
Emile Vauge
71cec1580b Fix stats responseRecorder Hijacker
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-15 09:17:33 +02:00
Emile Vauge
ffe1104851 Merge pull request #1588 from containous/fix-exported-fields-providers
Fix exported fields providers
2017-05-11 22:58:00 +02:00
Emile Vauge
aa4ed088bb Unexport Kvclient & StoreType from kv Provider
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-11 19:33:32 +02:00
Emile Vauge
3a4ec19817 Add missing description tag
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-11 19:33:32 +02:00
Timo Reimann
d2b204a075 Merge pull request #1581 from timoreimann/1-3-kubernetes-ignore-missing-pass-host-header-annotation
[Kubernetes] Ignore missing pass host header annotation. [v1.3 - CHERRY-PICK]
2017-05-11 17:43:14 +02:00
Timo Reimann
fe6c35bc6b [Kubernetes] Ignore missing pass host header annotation.
A missing annotation would previously be handled in the default error
case, causing a noisy warning-level log message to be generated each
time.

We add another case statement to ignore the case where the annotation is
missing from the annotations map.

Also piggybacking a minor improvement to the log message.
2017-05-10 19:32:45 +02:00
Ludovic Fernandez
3fd6da06e0 Merge pull request #1556 from atbore-phx/hf-travis
[CI ] to run once travis before_deploy
2017-05-05 15:19:55 +02:00
Attilio Borello
95502aeec3 hot fix for release, travis runs before_deploy for each provider! we add a condition to run once 2017-05-05 14:17:08 +02:00
Ludovic Fernandez
58c786ca8c Merge pull request #1552 from atbore-phx/new-ci
[CI] Add SemaphoreCI
2017-05-05 09:33:43 +02:00
Attilio Borello
b6916d2f8c added initial ci conf 2017-05-04 22:04:20 +02:00
Ludovic Fernandez
840c131a98 Merge pull request #1546 from atbore-phx/rf-travis-ci
[CI] Enhance cross-binary builds and parallelism
2017-05-04 21:28:10 +02:00
Attilio Borello
219bcec40f crossbinary default is now executed before deploy using multiple make jobs in parallel 2017-05-04 20:23:48 +02:00
Ludovic Fernandez
ccda550ab1 Merge pull request #1553 from containous/prepare-release-v1.3.0-rc1
Prepare release v1.3.0-rc1
2017-05-04 20:15:20 +02:00
Emile Vauge
b5e73cfa07 Prepare release v1.3.0-rc1 2017-05-04 18:17:54 +02:00
Emile Vauge
ba928dd459 Merge pull request #1241 from vholovko/healthcheck_changes
using more sensible consul blocking query to detect health check changes
2017-05-04 17:25:12 +02:00
Volodymyr Holovko
6fd40dbaa9 Using more sensible consul blocking query to detect health check changes 2017-05-04 16:54:27 +02:00
Ludovic Fernandez
6ad273b9fa Merge pull request #1542 from maxwo/working-ui
Working UI
2017-05-04 02:38:45 +02:00
Maxime Wojtczak
5500658f5a feat(UI) : Working UI.
chore(Build) : Add Babel for build.
chore(Babel) : Add babel configuration.
style(Code) : Enhance code style.
2017-05-04 01:12:46 +02:00
Ludovic Fernandez
b4f9e3890f Merge pull request #1535 from atbore-phx/crossbinary-parallel
Makefile target to enable parallel jobs
2017-05-04 00:47:38 +02:00
Attilio Borello
df6741aeeb Makefile target to enable parallel jobs
- fixed dependencies order and renamed Makefile target
- extracted docker run params into DOCKER_RUN_OPTS
- crossbinary-default contains 64bit Linux, Win and Darwin
- crossbinary-others contains 32bit Linux, Win, Darwin and 32/64bit *bsd
- added dependencies to crossbinary-default and crossbinary-others targets
2017-05-04 00:02:45 +02:00
Ludovic Fernandez
5535318cda Merge pull request #1538 from containous/merge-v1.2.3-master
Merge v1.2.3 master
2017-05-03 23:49:47 +02:00
Emile Vauge
4e186cecf9 Merge v1.2.3 master 2017-05-03 23:24:53 +02:00
Emile Vauge
8ac281f9e3 Prepare release v1.2.3
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-03 22:53:58 +02:00
Emile Vauge
e7a73d3fb3 Fix too many redirect
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-03 22:53:58 +02:00
Emile Vauge
ca9e36ebe3 Prepare release v1.2.2
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-03 22:53:58 +02:00
Adam Geiger
138fea17ed Fix redirect empty backend
Issue-#679
2017-05-03 22:53:58 +02:00
Emile Vauge
bf3f6e2029 Fix Docker filter empty rule
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-03 22:53:58 +02:00
Emile Vauge
ec245d604a Fix postLoadConfig
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-05-03 22:53:58 +02:00
Emile Vauge
69e081f40f Merge pull request #1541 from containous/revert-73a1b17
Revert "First stage of access logging middleware.  Initially without …
2017-05-03 19:35:49 +02:00
Emile Vauge
82651985c4 Revert "First stage of access logging middleware. Initially without any output appenders."
This reverts commit 73a1b172ed.
2017-05-03 17:30:31 +02:00
Ludovic Fernandez
a5384bae47 Merge pull request #1540 from containous/marathon-add-tests-lost-during-1320-rebase
Add tests lost during PR 1320.
2017-05-03 17:15:10 +02:00
Timo Reimann
1dcf8d2ea6 Add tests lost during PR 1320.
The tests part of this change were originally in PR 1320 but got lost
during one of the rebases. Let's bring them back in.
2017-05-03 16:27:21 +02:00
Ludovic Fernandez
e86df016c3 Merge pull request #1537 from ldez/refactor-git-alias-safe
refactor: fix for PR with master branch.
2017-05-03 16:24:38 +02:00
Fernandez Ludovic
72baf746f4 refactor: fix for PR with master branch. 2017-05-03 15:54:43 +02:00
Ludovic Fernandez
91b4b47f04 Merge pull request #1523 from tanyadegurechaff/make-port-deterministic
Make port deterministic
2017-05-03 15:53:46 +02:00
tanyadegurechaff
79cbe56a41 Make port deterministic 2017-05-03 15:28:53 +02:00
Ludovic Fernandez
f621d7a2c4 Merge pull request #1525 from guilhem/fix-watchdog
Fix systemd watchdog feature
2017-05-03 15:25:15 +02:00
Guilhem Lettron
3c33eab35e Fix systemd watchdog feature
Commit coreos/go-systemd@0c088e introduce cleaning environment.
First usage of sdnotify (for type=notify) was clearing NOTIFY_SOCKET environment variable.
sdnotify in watchdog was unable to ping back.

Fix #1353
2017-05-03 14:44:51 +02:00
Ludovic Fernandez
b67a27d0c7 Merge pull request #1527 from yyekhlef/master
feat(rancher): added constraint management for rancher provider
2017-05-03 14:32:01 +02:00
Youcef Yekhlef
8de107866f feat(rancher): added constraint management for rancher provider 2017-05-03 13:48:44 +02:00
Ludovic Fernandez
b5283391dd Merge pull request #1488 from alpe/k8s-auth
Add basic auth to kubernetes provider
2017-05-03 13:37:05 +02:00
Fernandez Ludovic
420a6db3b4 doc: add k8s basic auth. 2017-05-03 13:18:40 +02:00
Alex Peters
89da3b15a4 Add basic auth to kubernetes provider 2017-05-03 13:18:40 +02:00
Emile Vauge
dcc4d92983 Merge pull request #1524 from jangie/update-dep-go-marathon
[Marathon] Bump go-marathon dep
2017-05-03 13:06:36 +02:00
Bruce Lee
12c2d398a7 retry using 'script/glide.sh update'
fix docker dependency

remove unneeded docker dependency files

further cleanup
2017-05-03 11:43:37 +02:00
jangie
4e238280bc [Marathon] Bump go-marathon dep
attempt to remove glide from integration

glide trim

Revert "attempt to remove glide from integration"

This reverts commit c5b42b6cdebb44e730080a0cf20a871c11ef095b.
2017-05-03 11:43:37 +02:00
Ludovic Fernandez
bd6056c269 Merge pull request #1534 from containous/revert-1464-vendor-autogen
Revert "Vendor generated file"
2017-05-03 10:40:38 +02:00
Fernandez Ludovic
acb0492e26 Merge pull request #1464 from vdemeester/vendor-autogen 2017-05-03 10:02:14 +02:00
Emile Vauge
a0d6594e99 Merge pull request #1464 from vdemeester/vendor-autogen
Vendor generated file
2017-05-01 19:07:15 +02:00
Vincent Demeester
65f81990a7 Update script to use /usr/bin/env bash…
… instead of /bin/bash, to work better on more platforms.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-05-01 18:32:40 +02:00
Vincent Demeester
1b85dd0455 Vendor generated file
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-05-01 18:32:40 +02:00
Emile Vauge
bec45bc7d6 Merge pull request #1516 from ldez/refactor/documentation-review
doc: small documentation review
2017-05-01 18:32:20 +02:00
Fernandez Ludovic
4c4b05d024 refactor: small documentation review 2017-05-01 18:09:22 +02:00
Ludovic Fernandez
228ad9a244 Merge pull request #1517 from gottwald/safe-tests
Add unit tests for package safe
2017-05-01 17:33:16 +02:00
Ingo Gottwald
2f06f339ec Add unit tests for package safe
Also fix a bug in the code found due to the tests.
2017-05-01 16:21:26 +02:00
Emile Vauge
eefcf026d2 Merge pull request #1515 from ldez/github-template-again
doc: enhance Github templates.
2017-05-01 16:08:14 +02:00
Fernandez Ludovic
ccb1a4ff8c doc: enhance Github templates.
- suppress the mini user guide.
- explain the 'traefik bug' command.
2017-05-01 15:35:57 +02:00
Emile Vauge
78f1b4216e Merge pull request #1343 from uqf/improve-rancher-provider
Improve rancher provider handling of service and container health states
2017-05-01 12:34:59 +02:00
Matthew Kelch
44db6e9290 mprove Rancher provider functionality:
- Improves default filtering behavior to filter by container health/healthState
- Optionally allows filtering by service health/healthState
- Allows configuration of refresh interval
2017-04-29 15:37:54 -04:00
Timo Reimann
e2fdc27d64 Merge pull request #1338 from containous/add-global-option-for-healthcheck-interval
Add global health check interval parameter.
2017-04-28 21:35:29 +02:00
Timo Reimann
25345427c3 Add global health check interval parameter.
The new parameter allows to set a health check interval valid for all
backends. Custom values set per provider may override the global one.
2017-04-28 20:51:29 +02:00
Timo Reimann
ce492895e2 Merge pull request #1320 from containous/configure-healthcheck-via-marathon-label
Make Traefik health checks label-configurable with Marathon.
2017-04-28 18:59:35 +02:00
Timo Reimann
5d43b9e16a Add HealthCheckSuite to list of integration tests. 2017-04-28 18:17:25 +02:00
Timo Reimann
71a2c8bdcd Fix health check integration test suite typo. 2017-04-28 18:17:25 +02:00
Timo Reimann
8fd6160758 Fix health check path key name in Marathon template. 2017-04-28 18:17:25 +02:00
Timo Reimann
d57f83c31c Make Traefik health checks label-configurable with Marathon.
For the two existing health check parameters (path and interval), we add
support for Marathon labels.

Changes in detail:

- Extend the Marathon provider and template.
- Refactor Server.loadConfig to reduce duplication.
- Refactor the healthcheck package slightly to accommodate the changes
  and allow extending by future parameters.
- Update documentation.
2017-04-28 18:17:25 +02:00
Ludovic Fernandez
441d5442a1 Merge pull request #1339 from seguins/928-fix-regex-pathstrip
Fix regex with PathStrip
2017-04-28 18:01:05 +02:00
Stéphane Seguin
bf3673879f Fix regex with PathStrip 2017-04-28 17:33:14 +02:00
Ludovic Fernandez
74925ba996 Merge pull request #1357 from tcolgate/libkvuname
Add libkv Username and Password
2017-04-28 16:51:41 +02:00
Tristan Colgate
de6d771bc2 Add libkv Username and Password 2017-04-28 16:28:57 +02:00
Ludovic Fernandez
2f1a7cbf26 Merge pull request #1436 from Regner/1307-fix-k8s-tests-missing-endpoints
Updating Kubernetes tests to properly test missing endpoints code path
2017-04-28 15:54:33 +02:00
Regner Blok-Andersen
d24ba90900 Updating Kubernetes tests to properly test missing endpoints code path
This fixes #1307
2017-04-28 15:25:03 +02:00
Ludovic Fernandez
9ed55e9eae Merge pull request #1337 from SantoDE/fix/rancher_docs
make docs more clear about how to work with the current api
2017-04-28 10:40:29 +02:00
Manuel Laufenberg
a0c3d6a421 make docs more clear about how to work with the current api 2017-04-28 10:21:18 +02:00
Ludovic Fernandez
521e295349 Merge pull request #1374 from ssttevee/path-replace-rule
Add Path Replacement Rule
2017-04-27 10:38:41 +02:00
ssttevee
aa8375e82b added path replacement rule 2017-04-26 23:33:32 -07:00
Timo Reimann
5a8215a1e4 Merge pull request #1345 from diegooliveira/IP-Per-Task-Fix-Hostname
[Marathon] Detect proper hostname automatically.
2017-04-26 12:14:01 +02:00
Timo Reimann
7eb3051a57 Improve and extend TestGetBackendServer.
- Cover error cases.
- Use sub-tests.
2017-04-26 11:35:30 +02:00
Timo Reimann
a4355569af Extract index functionality into generic helper function.
Allows to move specific test cases to dedicated tests for new function.
2017-04-26 11:35:30 +02:00
Timo Reimann
16c86022bb Cosmetic changes. 2017-04-26 11:35:30 +02:00
Timo Reimann
e615e833bc Use go-spew to display diffs. 2017-04-26 11:35:30 +02:00
Diego de Oliveira
592a12dca2 Fix unsound behavior
The IP-Per-Task feature changed the behavior for
clients without this configuration (using the task IP instead
of task hostname). This patch make the new behavior available
just for Mesos installation with IP-Per-Task enabled. It also
make it possible to force the use of task's hostname.
2017-04-26 11:35:30 +02:00
Timo Reimann
97a3564945 Merge pull request #1497 from containous/re-exclude-dist-traefik-in-dockerignore
Re-exclude /dist/traefik from .dockerignore.
2017-04-26 10:34:20 +02:00
Timo Reimann
f1ee471b6b Re-exclude /dist/traefik from .dockerignore.
Required for the 'image' Makefile target to succeed since it copies the
binary into the image.
2017-04-26 10:01:43 +02:00
Timo Reimann
750fa22cff Merge pull request #1474 from containous/marathon-check-port-label-overwrite-earlier
Check for explicitly defined Marathon port first.
2017-04-26 03:21:33 +02:00
Timo Reimann
099d605aed Check for explicitly defined Marathon port first.
Previously, we did the check too late resulting in the traefik.port
label not being effective.

The change comes with additional refactorings in production and tests.
2017-04-25 23:18:30 +02:00
Timo Reimann
f1bc80ca12 Change getLabel signature to return bool instead of error.
The comma ok idiom fits better.
2017-04-25 23:18:30 +02:00
Timo Reimann
49a9aeb95f Merge pull request #1489 from containous/docker-move-test-providers-into-run-body
Move Docker test provider instantiation into t.Run body.
2017-04-25 15:30:37 +02:00
Timo Reimann
25abf8b8f8 Stop retrying unit tests on Travis. 2017-04-25 14:56:43 +02:00
Timo Reimann
962fb908c0 Pass through TESTDIRS env var to Docker build container. 2017-04-25 14:56:43 +02:00
Timo Reimann
b44aca64e3 Move Docker test provider instantiation into t.Run body. 2017-04-25 14:56:43 +02:00
Ludovic Fernandez
34b21b9374 Merge pull request #1482 from ldez/docs/github-template
doc: enhance GitHub template.
2017-04-25 12:10:10 +02:00
Fernandez Ludovic
972579e2a0 refactor(bugCmd): update issue template.
- fix collides with imported package name.
2017-04-25 11:14:31 +02:00
Fernandez Ludovic
ccff8a80f5 doc: enhance GitHub template.
- add issue and PR guide.
- rewrite templates
2017-04-25 11:14:31 +02:00
Ludovic Fernandez
4f2a2d573d Merge pull request #1486 from containous/fix-consul-catalog-flags
Fix Consul catalog prefix flags
2017-04-25 11:13:28 +02:00
Emile Vauge
af1d0a7dce Fix Consul catalog prefix flags
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-25 10:51:03 +02:00
Vincent Demeester
37e40bc776 Merge pull request #1470 from vdemeester/update-dockerignore
Update dockerignore to ignore dist and sites
2017-04-25 09:55:24 +02:00
Vincent Demeester
d9fd412e0e Update dockerignore ignore dist and sites
As of now, it does nothing (`/dist/` doesn't filter the dist folder)
and sending anything from `dist` doesn't make sense as it's mounted
anyway.

Removing the traefik binary from whitelist as the integration script
compiles the binary before running, so we don't need to send it via
the build context.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-25 09:02:07 +02:00
Emile Vauge
4bc2f17b08 Merge pull request #1368 from containous/update-doc
License 2017, Træfɪk => Træfik
2017-04-24 16:20:55 +02:00
Emile Vauge
d1b65adfb1 Traefik logo license
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-24 15:34:12 +02:00
Emile Vauge
19a7d22eef License 2017, Træfɪk => Træfik
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-24 15:12:44 +02:00
Vincent Demeester
6012a0f3c5 Merge pull request #1437 from ldez/feat/backends-filter
feat(webui): Dashboard filter
2017-04-24 10:25:46 +02:00
Fernandez Ludovic
4e81d41d06 doc: update web ui documentation
- update web ui dev documentation
- update Dashboard screenshot.
2017-04-24 10:04:58 +02:00
Fernandez Ludovic
f4579e5f12 refactor: clean code
- remove dead code
- replace Fprintf by Fprint.
2017-04-24 10:04:57 +02:00
Fernandez Ludovic
a8cbe7ef5e feat(webui): Add dashboard filter.
- Convert Object properties to and array for backends and frondends for each providers.
- Remove unused parameters.
- Add filter.
2017-04-24 10:04:57 +02:00
Timo Reimann
6ba17847ab Merge pull request #1179 from gstackio/master
Fix error in documentation for Docker labels
2017-04-23 02:30:53 +02:00
Benjamin Gandon
378a34c454 Fix error in documentation for Docker labels 2017-04-23 01:58:26 +02:00
Timo Reimann
f38d117a31 Merge pull request #1408 from hmrc/access-logging
New access logger.
2017-04-23 01:57:41 +02:00
Richard Shepherd
73a1b172ed First stage of access logging middleware. Initially without any output appenders. 2017-04-23 00:46:45 +02:00
Timo Reimann
4310bdf3ca Merge pull request #1458 from ben-st/update_readme
update wording
2017-04-23 00:44:44 +02:00
Benjamin
6cb8df9d1e update wording 2017-04-22 23:49:38 +02:00
Timo Reimann
93e123b489 Merge pull request #1467 from mattcollier/patch-1
Fix typo in command line help.
2017-04-22 23:01:03 +02:00
mattcollier
8764c43eaf Fix typo in command line help. 2017-04-21 14:01:45 +02:00
Timo Reimann
10e22c0b3f Merge pull request #1469 from containous/improve-frontend-rule-documentation
Improve documentation for frontend rules.
2017-04-21 01:10:13 +02:00
Timo Reimann
051f0c6855 Improve documentation for frontend rules.
Includes guidelines on proper usage of the more complex path matchers.
2017-04-21 00:30:27 +02:00
Timo Reimann
809103f4b2 Merge pull request #1473 from mattcollier/patch-2
Correct typo in code comment.
2017-04-20 22:01:16 +02:00
mattcollier
b7c2e2d3f1 Correct typo and use Godoc convention in comment. 2017-04-20 14:02:29 -04:00
Vincent Demeester
d866a62b56 Merge pull request #1468 from containous/traefik-pronunciation-pages
Mention Traefik pronunciation in docs too.
2017-04-20 14:00:44 +02:00
Timo Reimann
22ac60205a Mention Traefik pronunciation in docs too.
Also replace Træfɪk with Træfik.
2017-04-20 12:08:12 +02:00
Vincent Demeester
de557d031b Merge pull request #1449 from vdemeester/more-extraction
Extract some code in packages
2017-04-20 11:37:40 +02:00
Vincent Demeester
7fcb7b86d3 Extract some code in packages
- This will help split stuff in smaller, better tested packages
- This moves some stuff like the traefik command to package `cmd`

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-20 10:06:41 +02:00
Vincent Demeester
9c9015a7b1 Merge pull request #1398 from containous/fix-default-timeouts-for-marathon-provider
Fix default timeouts for Marathon provider.
2017-04-20 08:37:20 +02:00
Timo Reimann
360e8e19ce Fix default timeouts for Marathon provider.
The timeouts were given without a unit, which caused nanoseconds scale
to be applied when we switched the type from int to flaeg.Duration.
2017-04-20 01:51:10 +02:00
Timo Reimann
dd52ee9f9b Merge pull request #1147 from SantoDE/feature-http-basic-auth-frontend
Add Basic Auth per Frontend.
2017-04-20 00:26:39 +02:00
Manuel Laufenberg
8a892b21e1 Add Basic Auth per Frontend for Rancher & Docker Dynamic Provider 2017-04-19 21:05:43 +02:00
Vincent Demeester
4e0f131fcd Merge pull request #1453 from martinbaillie/rancher-provider-pagination-fixes
Fix Rancher API pagination limits
2017-04-19 13:36:55 +02:00
Martin Baillie
d1ee72b308 Merge branch 'master' into rancher-provider-pagination-fixes 2017-04-19 20:47:30 +10:00
Vincent Demeester
f03a9e502f Merge pull request #1444 from vdemeester/extract-providers
Extract providers to their own packages
2017-04-18 22:54:49 +02:00
Vincent Demeester
542c3673e4 Extract providers to their own package
This is just doing that and making it compile :)

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-18 13:24:17 +02:00
Vincent Demeester
2d00758b2e Merge pull request #1455 from martinbaillie/fix-traefik-sample-toml
Fix Rancher backend left in uncommented state
2017-04-18 11:56:37 +02:00
Martin Baillie
73f09f389e Fix Rancher API pagination limits
This fix allows the Traefik Rancher provider to obtain a complete view
of the environments, services and containers being managed by the
Rancher deployment.
2017-04-18 19:48:43 +10:00
Martin Baillie
29bada9ae3 Fix Rancher backend left in uncommented state 2017-04-18 15:00:18 +10:00
Vincent Demeester
4ce2c8cc34 Merge pull request #1448 from vdemeester/fix-master-windows-compilation
Update golang.org/x/sys to fix windows compilation
2017-04-17 20:44:07 +02:00
Vincent Demeester
b02b11a606 Update golang.org/x/sys to fix windows compilation
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-17 20:08:40 +02:00
Vincent Demeester
e38fa25412 Merge pull request #1447 from vdemeester/dont-binary-twice
[ci] Don't run binary twice
2017-04-17 19:34:39 +02:00
Vincent Demeester
38b2362a31 Don't run binary twice
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-17 18:51:37 +02:00
Vincent Demeester
13754f06e3 Merge pull request #1445 from vdemeester/pull-in-pre
Pull images before running CI
2017-04-17 18:13:10 +02:00
Vincent Demeester
ade223cf2e Pull images before running CI
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-17 17:28:34 +02:00
Vincent Demeester
2118f6992a Merge pull request #1440 from vdemeester/docker-provider-refacto
Few refactoring around the docker provider
2017-04-17 17:28:13 +02:00
Vincent Demeester
b04ba36682 Update some docker provider test
- Split the file into smaller ones (docker, swarm and service tests)
- Use some builder to reduce a little bit the noise for creating containers

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-17 15:40:55 +02:00
Vincent Demeester
3f293ee25b Move docker provider to its own package 👼
Makes it simpler to manage :)

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2017-04-17 15:40:55 +02:00
Timo Reimann
dc01094863 Merge pull request #1442 from martinbaillie/master
Pass stripped prefix downstream as header (#985)
2017-04-17 09:07:13 +02:00
Martin Baillie
fa683fa7e4 Pass stripped prefix downstream as header 2017-04-16 19:24:26 +10:00
Timo Reimann
1da47dfcbb Merge pull request #1404 from aolwas/k8s-rbac-doc-update
Add documentation for k8s RBAC configuration.
2017-04-13 01:13:52 +02:00
Maxime Cottret
fc3cc9a919 Add documentation for k8s RBAC configuration 2017-04-13 00:27:16 +02:00
Emile Vauge
12a0026e21 Merge pull request #1383 from containous/merge-v1.2.1-master
Merge v1.2.1 master
2017-04-12 09:13:03 +02:00
Emile Vauge
aeb17182b4 Merge v1.2.1-master
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:56 +02:00
Emile Vauge
a590155b0b Prepare release v1.2.1
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Emile Vauge
87ce060737 bump lego 0e2937900
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Timo Reimann
f2297dd3ed k8s: Do not log service fields when GetService is failing.
Update tests too.
2017-04-11 22:36:55 +02:00
Emile Vauge
2cd4c82092 Prepare release v1.2.0
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Emile Vauge
6edc0926eb sub-tests + Fatalf/Errorf
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Emile Vauge
a456d36cc6 Add Docker task list test
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
yshay
5c2d91ab84 Add check on task status in addition to desired status 2017-04-11 22:36:55 +02:00
Sebastian
a73fee50dc Docker: Added warning if network could not be found (#1310)
* Added warning if network could not be found

* Removed regex import from master

* Corrected wrong function call
2017-04-11 22:36:55 +02:00
Regner Blok-Andersen
b02393915e Abort Kubernetes Ingress update if Kubernetes API call fails (#1295)
* Abort Kubernetes Ingress update if Kubernetes API call fails

Currently if a Kubernetes API call fails we potentially remove a working service from Traefik. This changes it so if a Kubernetes API call fails we abort out of the ingress update and use the current working config. Github issue: #1240

Also added a test to cover when requested resources (services and endpoints) that the user has specified don’t exist.

* Specifically capturing the tc range as documented here: https://blog.golang.org/subtests

* Updating service names in the mock data to be more clear

* Updated expected data to match what currently happens in the loadIngress

* Adding a blank Servers to the expected output so we compare against that instead of nil.

* Replacing the JSON test output with spew for the TestMissingResources test to help ensure we have useful output incase of failures

* Adding a temporary fix to the GetEndoints mocked function so we can override the return value for if the endpoints exist.

After the 1.2 release the use of properExists should be removed and the GetEndpoints function should return false for the second value indicating the endpoint doesn’t exist. However at this time that would break a lot of the tests.

* Adding quick TODO line about removing the properExists property

* Link to issue 1307 re: properExists flag.
2017-04-11 22:36:55 +02:00
Emile Vauge
b99a919bb4 Refactor k8s client config
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Emile Vauge
51f3f6ba9c Removed unused log
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Emile Vauge
736f9b30ef Fix default config in generic Mesos provider
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 22:36:55 +02:00
Timo Reimann
b385ffaee7 Revert "Pass context to ListReleases when checking for new versions."
This reverts commit 07db6a2df1.
2017-04-11 22:36:55 +02:00
Timo Reimann
b02e289734 Update github.com/containous/oxy only. 2017-04-11 22:36:55 +02:00
Timo Reimann
fd1cf2484c Reset glide files to versions from upstream/v1.2. 2017-04-11 22:36:55 +02:00
Attila Kanto
5250c9c04d Update vulcand and pin deps in glide.yaml 2017-04-11 22:36:55 +02:00
Timo Reimann
e011792a90 Pass context to ListReleases when checking for new versions.
Required by go-github update.
2017-04-11 22:36:55 +02:00
Timo Reimann
a507cb4835 Rename health check URL parameter to path.
Also improve documentation.
2017-04-11 22:36:55 +02:00
Matevz Mihalic
f324983946 Fix metrics registering 2017-04-11 22:36:55 +02:00
Owen Marshall
c876462eb0 Chunk taskArns into groups of 100
If the ECS cluster has > 100 tasks, passing them to
ecs.DescribeTasksRequest() will result in the AWS API returning
errors.

This patch breaks them into chunks of at most 100, and calls
DescribeTasks for each chunk.

We also return early in case ListTasks returns no values; this
prevents DescribeTasks from throwing HTTP errors.
2017-04-11 22:36:55 +02:00
Timo Reimann
ec7ba15955 Docs: Update default value for DefaultMaxIdleConnsPerHost. 2017-04-11 22:36:55 +02:00
dtomcej
ef83a5936d update oxy hash 2017-04-11 22:36:55 +02:00
Manuel Laufenberg
8d650da2f8 Bump go-rancher version 2017-04-11 22:36:55 +02:00
Emile Vauge
bd127168b3 Merge pull request #1421 from containous/move-crossbinary-travis-deploy
Move make cross binary to Travis deploy step
2017-04-11 22:35:49 +02:00
Emile Vauge
1ecdadb283 Move make cross binary to Travis deploy step
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-04-11 20:47:25 +02:00
Emile Vauge
d8c21639f7 Merge pull request #1407 from containous/glide-sh-push-get-param-to-array
glide.sh: Push argument to GLIDE_ARGS array.
2017-04-10 20:37:35 +02:00
Timo Reimann
d2df47d382 glide.sh: Push argument to GLIDE_ARGS array.
The array is empty in the beginning, so referencing ${GLIDE_ARGS[@]}
produces an error due to nounset.
2017-04-10 10:42:33 +02:00
Vincent Demeester
0cc3d05515 Merge pull request #1319 from containous/start-healthcheck-early
Start health checks early.
2017-04-08 12:41:36 +02:00
Timo Reimann
60ea9199e5 Start health checks early.
Do not wait a full tick cycle to execute the first health check.

Additional changes:

- Make request timeout configurable (for testing purposes).
- Support synchronizing on health check goroutine termination through an
  internal wait group (for testing purposes).
- Stop leaking by closing the HTTP response body.
- Extend health check logging and use WARNING level for (continuously)
  failing health checks.
2017-04-07 19:13:15 +02:00
Emile Vauge
637c7e250c Merge pull request #1178 from errm/k8s-client-2
Upgrade k8s.io/client-go to version 2
2017-04-07 14:22:50 +02:00
Ed Robinson
6f4c5dd4ce Upgrade k8s.io/client-go to version 2 2017-04-07 11:52:18 +01:00
Ed Robinson
a3b95f798b Update lego 2017-04-07 11:52:18 +01:00
Ed Robinson
65284441fa Update dependencies 2017-04-07 11:52:18 +01:00
Emile Vauge
51e4dcbb1f Merge pull request #1367 from seguins/chart-k8s
Add documentation about k8s Helm Chart
2017-04-07 11:53:30 +02:00
Stéphane Seguin
e38bf0accb Add documentation about k8s chart 2017-04-06 21:52:39 +02:00
Emile Vauge
08c1871c98 Merge pull request #1394 from containous/nicgrayson-master
Allow traefik.port to not be in the list of marathon ports
2017-04-06 20:57:58 +02:00
Nic Grayson
4eb779e596 Allow traefik.port to not be in the list of marathon ports 2017-04-06 18:47:35 +02:00
Emile Vauge
e1aa16ae70 Merge pull request #1196 from klausenbusk/url
kv: Ignore backend servers with no url
2017-04-06 11:14:57 +02:00
Kristian Klausen
b4dfb7223b kv: Extend test with support for specifying custom error for Get/List 2017-04-06 10:28:11 +02:00
Kristian Klausen
f621a46a2e kv: Log error when checking existence of server url key 2017-04-06 10:28:11 +02:00
Kristian Klausen
c864d80270 kv: Add test for server without url key 2017-04-06 10:28:11 +02:00
Kristian Klausen
020a8e31ab kv: Ignore backend servers with no url
Currently with a kv tree like:
/traefik/backends/b1/servers/ẁeb1
/traefik/backends/b1/servers/web2
/traefik/backends/b1/servers/web2/url
Traefik would try to forward traffic to web1, which is impossible as
traefik doesn't know the url of web1.

This commit solve that, by ignoring backend server with no url "key"
when generating the config.

This is very useful, for people who use etcd TTL feature. They can then
just "renew" the url key every X second, and if the server goes down, it
is automatic removed from traefik after the TTL.
2017-04-06 10:28:11 +02:00
Timo Reimann
69c31276f2 Merge pull request #1386 from mihaitodor/patch-1
Fix typo in server.go
2017-04-04 21:37:54 +02:00
Mihai Todor
06c47134c9 Fix typo
Fix "loadd-balancer" typo in log debug message in server.go
2017-04-04 17:23:55 +01:00
Ben Parli
c9d23494b9 Add IdleConnTimeout to Traefik's http.server settings (#1340)
* Add IdleTimeout setting to http.server

Without such a timeout there is a risk of resource leakage from piling up connections, particularly when exposing Traefik to the Internet.

Set the default to be 180 seconds

* Add IdleConnTimeout to Traefik's http.server settings

Without enforcing a timeout Traefik is susceptible to resource leakage, particularly when deployed as a public facing proxy exposed to the Internet.

Set the default to be 180 seconds

* tweak

* Update configuration.go

* add some documentation for the idletimeout setting

* need to cast idletimeout

* update doc to refect format specifics
2017-04-04 11:36:23 +02:00
Timo Reimann
7d256c9bb9 Merge pull request #1350 from containous/toml-compatible-duration-type
Use TOML-compatible duration type.
2017-04-03 19:30:33 +02:00
Timo Reimann
056fe9ac0a Switch duration configuration parameters over to flaeg.Duration. 2017-04-03 18:36:23 +02:00
Timo Reimann
e375ba98f0 Update vendored dependencies. 2017-04-03 18:36:23 +02:00
Timo Reimann
d6d93db13b Update to latest github.com/containous/flaeg. 2017-04-03 18:36:23 +02:00
Emile Vauge
3389908238 Merge pull request #1235 from tcoupin/feat-use-docker-compose-labels
Use docker-compose labels for frontend and backend names
2017-04-03 11:46:20 +02:00
tcoupin
5c16860486 Use service.project.domain instead of project-service.domain 2017-04-03 11:00:04 +02:00
tcoupin
0a7f9b5a71 Use docker-compose labels for frontend and backend names 2017-04-03 11:00:04 +02:00
Timo Reimann
df685fa050 Merge pull request #1324 from containous/ask-for-debug-log-output-in-template
Append template section asking for debug log output.
2017-04-01 07:22:42 +02:00
Timo Reimann
2c079b3d6f Append template section asking for debug log output. 2017-03-31 17:38:48 +02:00
Timo Reimann
35973f1243 Merge pull request #1369 from Starefossen/patch-2
Make toml Bucket array homogeneous
2017-03-31 17:06:45 +02:00
Hans Kristian Flaatten
9281f4fbbc Make toml Bucket array homogeneous 2017-03-31 14:01:56 +02:00
Timo Reimann
0e0a231e5a Merge pull request #1303 from ruslansennov/patch-1
fix consul sample endpoints
2017-03-29 21:19:56 +02:00
Ruslan Sennov
b22716c5ba fix consul sample endpoints
It took few minutes to understand what is wrong, when I just uncommented sample config :)
2017-03-29 14:03:20 +02:00
Manuel Laufenberg
240b2be1a8 Merge pull request #1233 from tcoupin/feature-web-pathprefix
Feature web root path
2017-03-24 18:35:32 +01:00
tcoupin
c5125cee71 Add path parameter for web provider 2017-03-24 17:51:53 +01:00
Timo Reimann
1cf1fbf99b Merge pull request #1276 from kekoav/go-1.8-update-tls-ciphers
Update TLS Ciphers for Go 1.8
2017-03-24 13:58:26 +01:00
Kekoa Vincent
1ed68b1278 Updated available cipher suites for Go 1.8. 2017-03-24 09:37:46 +01:00
Timo Reimann
84e1ec6607 Merge pull request #1259 from containous/bump-go-1.8
Bump go 1.8
2017-03-24 09:34:29 +01:00
Emile Vauge
1140ee6c64 Update vendor dependencies
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-23 22:51:59 +01:00
Emile Vauge
8401cccff2 Replace mailgun/manners with go 1.8 graceful shutdown
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-23 22:47:29 +01:00
Emile Vauge
836f617286 Bump go 1.8
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-23 22:39:53 +01:00
Vincent Demeester
1bc8c9912e Merge pull request #1329 from containous/makefile-image-target-depend-on-binary
Make image Makefile target depend on binary instead of build.
2017-03-22 19:00:04 +01:00
Timo Reimann
b5430803b8 Make image Makefile target depend on binary instead of build.
build only builds the build container without the binary.
2017-03-22 16:33:02 +01:00
Vincent Demeester
a7bc8c8aa4 Merge pull request #1274 from sroze/patch-1
Change a word in the documentation
2017-03-22 09:48:32 +01:00
Samuel ROZE
9ab8e08d59 s/Hopefully/Fortunately/ 2017-03-21 22:44:54 +01:00
Emile Vauge
677899d9ff Merge pull request #1158 from tskinn/add-dynamodb-provider
add dynamodb backend
2017-03-17 18:02:02 +01:00
Taylor Skinner
72e35af39f add dynamo
Signed-off-by: Taylor Skinner <tskinn12@gmail.com>

add some comments

Signed-off-by: Taylor Skinner <tskinn12@gmail.com>

update readmes

make test runnable

Signed-off-by: Taylor Skinner <tskinn12@gmail.com>

make test

squash! add dynamo

add glide.lock

format imports

gofmt

update glide.lock

fixes for review

golint

clean up and reorganize tests

add dynamodb integration test

remove default region. clean up tests. consistent docs

forgot the region is required

DRY

make validate

update readme and commit dependencies
2017-03-16 10:12:26 -06:00
Timo Reimann
2a61c9049f Merge pull request #1257 from benoitf/docker-services
Allow multiple rules from docker labels containers with traefik.<servicename>.* properties
2017-03-14 10:31:58 +01:00
Florent BENOIT
1158eba7ac Adding docker labels traefik.<servicename>.* properties like
- traefik.mycustomservice.port=443
  -  traefik.mycustomservice.frontend.rule=Path:/mycustomservice
   - traefik.anothercustomservice.port=8080
  -  traefik.anothercustomservice.frontend.rule=Path:/anotherservice

all traffic to frontend /mycustomservice is redirected to the port 443 of the container while using /anotherservice will redirect to the port 8080 of the docker container

More documentation in the docs/toml.md file

Change-Id: Ifaa3bb00ef0a0f38aa189e0ca1586fde8c5ed862
Signed-off-by: Florent BENOIT <fbenoit@codenvy.com>
2017-03-14 08:45:47 +01:00
Emile Vauge
22c5bf7630 Merge pull request #1273 from timoreimann/rpr-force-with-lease
.github/rpr.sh: Use --force-with-lease instead of --force.
2017-03-11 11:36:37 +01:00
Timo Reimann
4148266ed0 .github/rpr.sh: Use --force-with-lease instead of --force.
This prevents accidentally overriding a branch that has been changed
remotely by another party.
2017-03-10 21:32:34 +01:00
Timo Reimann
6e8e597ff5 Merge pull request #1189 from krancour/usersfile
Allow usersFile to be specified for basic or digest auth
2017-03-10 07:45:39 +01:00
Kent Rancourt
7357417f48 Allow usersFile to be specified for basic or digest auth 2017-03-09 20:24:44 -05:00
Timo Reimann
91bf627275 Merge pull request #1144 from timoreimann/vendor-dependencies
Vendor dependencies.
2017-03-09 16:23:26 +01:00
Timo Reimann
55b57c736b Vendor integration dependencies. 2017-03-09 13:13:03 +01:00
Timo Reimann
dd5e3fba01 Vendor main dependencies. 2017-03-09 13:13:02 +01:00
Timo Reimann
49a09ab7dd Prepare for dependency vendoring.
- Add helper script to simplify glide usage.
- Add validation script for unwanted changes to vendoring.
- Relax/tighten up .{git,docker}ignore to cover vendored files properly.
- .validate: Protect from unbound variable in case of nounset setting.
- Install more recent hg version in the build container.
- Remove glide installation steps from Dockerfile.
- Update documentation.
2017-03-08 22:21:12 +01:00
Emile Vauge
dae28f7f17 Merge pull request #1227 from dtomcej/tighter-regex
Tighten regex match for wildcard certs [Addendum to #1018]
2017-03-07 16:59:52 +01:00
Daniel Tomcej
9cd76f122e remove dot from regex 2017-03-07 15:21:08 +01:00
Timo Reimann
920b5bb15d Support cluster-external Kubernetes client. (#1159)
Detect whether in-cluster or cluster-external Kubernetes client should
be used based on the KUBERNETES_SERVICE_{HOST,PORT} environment
variables.

Adds bearer token and CA certificate file path parameters.
2017-03-07 13:09:11 +01:00
Emile Vauge
3611818eda Add @trecloux to Maintainers (#1226) 2017-03-07 00:38:44 +01:00
Emile Vauge
7d83027954 Merge pull request #1208 from containous/merge-v1.2.0-rc2-master
Merge v1.2.0 rc2 master
2017-03-06 18:37:03 +01:00
Emile Vauge
ea190b6898 Prepare release v1.2.0-rc2
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-06 17:45:58 +01:00
Bruce Lee
aa75d5458d Revert "Ensure that we don't add balancees with no health check runs if there is a health check defined on it"
This reverts commit ad12a7264e.
2017-03-06 17:45:58 +01:00
Christophe Robin
4172a7c62e Add task parser unit test for docker provider 2017-03-06 17:45:58 +01:00
Christophe Robin
355b4706d3 Fix docker issues with global and dead tasks 2017-03-06 17:45:58 +01:00
Manuel Laufenberg
eb1ffae01b Small fixes and improvments 2017-03-06 17:45:58 +01:00
Emile Vauge
cc0733a4fa Fix stats race condition
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-06 17:45:58 +01:00
Luke Petre
c786bbbc5b Try harder to query all the possible ec2 instances, and filter on instance state / lack of IP address 2017-03-06 17:45:58 +01:00
Julien Salleyron
f87b1c2fcd Wrong tests docker images 2017-03-06 17:45:58 +01:00
Julien Salleyron
14fd53c915 Add doc 2017-03-06 17:45:58 +01:00
Julien Salleyron
aa2edcc6e5 Add some integration test 2017-03-06 17:45:58 +01:00
Julien Salleyron
6b6f010851 Add healthcheck interval 2017-03-06 17:45:58 +01:00
Rickard von Essen
5e8805f24d ECS: Docs - info about cred. resolution and required access policies
Added information about how AWS credentials are resolved and which
access rights is needed the Traefik ECS provider.
2017-03-06 17:45:58 +01:00
Emile Vauge
3848944d35 Fix travis deploy
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-06 17:45:58 +01:00
Emile Vauge
9d7df45b7c Changelog for v1.2.0-rc1
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-06 17:45:58 +01:00
Emile Vauge
7a164ed401 Add v1.2 codename
Signed-off-by: Emile Vauge <emile@vauge.com>
2017-03-06 17:45:57 +01:00
Regner Blok-Andersen
f530284031 Adding support for Traefik to respect the K8s ingress class annotation (#1182) 2017-03-03 20:30:22 +01:00
Timo Reimann
38c0cf7007 Merge pull request #1151 from timoreimann/refactor-k8s-rule-type-annotation-logic
Refactor k8s rule type annotation parsing/retrieval.
2017-03-03 18:48:59 +01:00
Timo Reimann
f3598e6b0f Refactor k8s rule type annotation parsing/retrieval.
- Move annotation logic into function.
- Constantify strings.
- Refactor TestRuleType.
- Add test for GetRuleTypeFromAnnotations.
2017-03-03 13:33:00 +01:00
Vincent Demeester
291ca860af Merge pull request #1216 from timoreimann/elaborate-on-regexp
Motivate and explain regular expression rules.
2017-03-03 10:09:30 +01:00
Timo Reimann
7d20871f0d Fix typos. 2017-03-03 00:27:33 +01:00
Timo Reimann
6942b063ee Motivate and explain regular expression rules. 2017-03-02 23:00:25 +01:00
Timo Reimann
e56bd27c1e Remove blank space. 2017-03-02 23:00:25 +01:00
Timo Reimann
a3beec6b9c Merge pull request #1214 from timoreimann/avoid-validate-glide-output-suppression
Evaluate glide-hash result without reading $?.
2017-03-02 23:00:01 +01:00
Timo Reimann
04a1ecc4f4 Evaluate glide-hash result without reading $?.
validate-glide is called with errexit enabled (in script/make.sh that
sources validate-glide), which means that grep returning a non-zero exit
code will cause the script to terminate prematurely. Thus, we will never
get to the point where we see the error message.

The fix is to embed the grep check directly inside the if statement.
2017-03-02 18:49:13 +01:00
Manuel Laufenberg
7707814f2e Merge pull request #1215 from timoreimann/add-timoreimann-to-maintainer-list
Add @timoreimann to list of maintainers.
2017-03-02 17:59:00 +01:00
Timo Reimann
4d4f2b62aa Add @timoreimann to list of maintainers. 2017-03-02 02:00:53 +01:00
Emile Vauge
5abffe402f Merge pull request #1194 from timoreimann/example-ip-addr-binding
Add Traefik TOML sample section on how to bind to specific IP addr.
2017-02-28 09:57:23 +01:00
Timo Reimann
38ec32a146 Add Traefik TOML sample section on how to bind to specific IP addr. 2017-02-25 21:44:01 +01:00
Vincent Demeester
d77ad42326 Merge pull request #1149 from Regner/kubernetes-support-externalname-service
Kubernetes support externalname service
2017-02-22 10:52:35 +01:00
Regner Blok-Andersen
4106f0fa9e Merge branch 'master' into kubernetes-support-externalname-service 2017-02-21 16:19:01 -08:00
Vincent Demeester
a0a0bf0577 Merge pull request #1170 from timoreimann/upgrade-go-marathon-to-v0.7.0
Upgrade dependencies.
2017-02-21 20:45:22 +01:00
Regner Blok-Andersen
71c7920d0f Merge branch 'master' into kubernetes-support-externalname-service 2017-02-21 10:02:34 -08:00
Timo Reimann
9bb1b01742 Upgrade dependencies.
Brings github.com/gambol99/go-marathon version 0.7.1.
2017-02-21 16:10:45 +01:00
Vincent Demeester
8c824680ce Merge pull request #1157 from solidnerd/fix-prometheus-in-traefik-example-toml
Fix prometheus metrics example
2017-02-21 09:52:27 +01:00
solidnerd
60b3f74be8 Fix prometheus metrics example
Traefik won’t start correctly if heterogeneous numbers in a toml array.  This commit makes all numbers homogene.

Signed-off-by: solidnerd <niclas@mietz.io>
2017-02-21 07:55:50 +01:00
Vincent Demeester
dfb09bf2ab Merge pull request #1172 from timoreimann/stop-considering-glide-lock-as-binary-in-git
Remove .gitattributes file.
2017-02-20 21:34:55 +01:00
Timo Reimann
98d6a43e1e Remove .gitattributes file.
Makes git diff Glide lock files as text, which is helpful to see changes
introduced by a 'glide update' run.
2017-02-18 22:56:24 +01:00
Regner Blok-Andersen
49466d0d14 Added documentation about defining the passing of host header globaly 2017-02-15 16:11:31 -08:00
Regner Blok-Andersen
66cc9a075c First pass of documentation for passHostHeader kubernetes annotation 2017-02-15 13:37:47 -08:00
Regner Blok-Andersen
1e10fc2e30 Simplifying else if statement to be cleaner 2017-02-14 14:57:09 -08:00
Regner Blok-Andersen
c8cf5f8c44 Added a test to make sure passing an invalid value to traefik.frontend.passHostHeader results in falling back correctly. 2017-02-14 11:54:27 -08:00
Regner Blok-Andersen
96e6c9cef2 Split the if/or statement when requesting endpoints from the k8s service so that it now provides two unique log statements. 2017-02-14 11:53:35 -08:00
Regner Blok-Andersen
931ee55e1d Added default case for PassHostHeader that logs a warning. 2017-02-14 11:52:54 -08:00
Regner Blok-Andersen
4d3aede5d3 Added tests for ingress passHostHeader annotation 2017-02-10 03:27:30 -08:00
Regner Blok-Andersen
0b1dd69b01 Added support for passHostHeader annotation on ingresses 2017-02-10 03:05:59 -08:00
Regner Blok-Andersen
0947aa901e Initial support for Kubernetes ExternalName service type 2017-02-09 17:25:38 -08:00
Vincent Demeester
01e3d7952a Merge pull request #1133 from timoreimann/build-binary-for-test-integration-makefile-target
Build binary for test-integration Makefile target.
2017-02-08 09:30:08 +01:00
Timo Reimann
84b224b9db Build binary for test-integration Makefile target. 2017-02-07 15:08:17 +01:00
5213 changed files with 1836370 additions and 5338 deletions

View File

@@ -1,5 +1,3 @@
dist/
vendor/
!dist/traefik
site/
**/*.test

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
glide.lock binary

View File

@@ -2,7 +2,7 @@
### Building
You need either [Docker](https://github.com/docker/docker) and `make` (Method 1), or `go` and `glide` (Method 2) in order to build traefik.
You need either [Docker](https://github.com/docker/docker) and `make` (Method 1), or `go` (Method 2) in order to build traefik. For changes to its dependencies, the `glide` dependency management tool and `glide-vc` plugin are required.
#### Method 1: Using `Docker` and `Makefile`
@@ -26,14 +26,14 @@ $ ls dist/
traefik*
```
#### Method 2: Using `go` and `glide`
#### Method 2: Using `go`
###### Setting up your `go` environment
- You need `go` v1.7+
- It is recommended you clone Træfɪk into a directory like `~/go/src/github.com/containous/traefik` (This is the official golang workspace hierarchy, and will allow dependencies to resolve properly)
- It is recommended you clone Træfik into a directory like `~/go/src/github.com/containous/traefik` (This is the official golang workspace hierarchy, and will allow dependencies to resolve properly)
- This will allow your `GOPATH` and `PATH` variable to be set to `~/go` via:
```
```bash
$ export GOPATH=~/go
$ export PATH=$PATH:$GOPATH/bin
```
@@ -42,27 +42,33 @@ This can be verified via `$ go env`
- You will want to add those 2 export lines to your `.bashrc` or `.bash_profile`
- You need `go-bindata` to be able to use `go generate` command (needed to build) : `$ go get github.com/jteeuwen/go-bindata/...` (Please note, the ellipses are required)
###### Setting up your `glide` environment
#### Setting up `glide` and `glide-vc` for dependency management
- Glide is not required for building; however, it is necessary to modify dependencies (i.e., add, update, or remove third-party packages)
- Glide can be installed either via homebrew: `$ brew install glide` or via the official glide script: `$ curl https://glide.sh/get | sh`
- The glide plugin `glide-vc` must be installed from source: `go get github.com/sgotti/glide-vc`
The idea behind `glide` is the following :
If you want to add a dependency, use `$ glide get` to have glide put it into the vendor folder and update the glide manifest/lock files (`glide.yaml` and `glide.lock`, respectively). A following `glide-vc` run should be triggered to trim down the size of the vendor folder. The final result must be committed into VCS.
- when checkout(ing) a project, run `$ glide install -v` from the cloned directory to install
(`go get …`) the dependencies in your `GOPATH`.
- if you need another dependency, import and use it in
the source, and run `$ glide get github.com/Masterminds/cookoo` to save it in
`vendor` and add it to your `glide.yaml`.
Dependencies for the integration tests in the `integration` folder are managed in a separate `integration/glide.yaml` file using the same toolset.
Care must be taken to choose the right arguments to `glide` when dealing with either main or integration test dependencies, or otherwise risk ending up with a broken build. For that reason, the helper script `script/glide.sh` encapsulates the gory details and conveniently calls `glide-vc` as well. Call it without parameters for basic usage instructions.
Here's a full example:
```bash
$ glide install --strip-vendor
# install the new main dependency github.com/foo/bar and minimize vendor size
$ ./script/glide.sh get github.com/foo/bar
# install another dependency, this time for the integration tests
$ ( cd integration && ../script/glide.sh get github.com/baz/quuz )
# generate (Only required to integrate other components such as web dashboard)
$ go generate
# Standard go build
$ go build
# Using gox to build multiple platform
$ gox "linux darwin" "386 amd64 arm" \
-output="dist/traefik_{{.OS}}-{{.Arch}}"
-output="dist/traefik_{{.OS}}-{{.Arch}}" \
./cmd/traefik
# run other commands like tests
```
@@ -89,7 +95,7 @@ Test success
```
For development purposes, you can specify which tests to run by using:
```
```bash
# Run every tests in the MyTest suite
TESTFLAGS="-check.f MyTestSuite" make test-integration
@@ -105,14 +111,12 @@ TESTFLAGS="-check.f MyTestSuite.*Test" make test-integration
More: https://labix.org/gocheck
##### Method 2: `go` and `glide`
##### Method 2: `go`
- Tests can be run from the cloned directory, by `$ go test ./...` which should return `ok` similar to:
```
ok _/home/vincent/src/github/vdemeester/traefik 0.004s
```
- Note that `$ go test ./...` will run all tests (including the ones in the vendor directory for the dependencies that glide have fetched). If you only want to run the tests for traefik use `$ go test $(glide novendor)` instead.
### Documentation
@@ -120,7 +124,7 @@ The [documentation site](http://docs.traefik.io/) is built with [mkdocs](http://
First make sure you have python and pip installed
```
```shell
$ python --version
Python 2.7.2
$ pip --version
@@ -129,13 +133,13 @@ pip 1.5.2
Then install mkdocs with pip
```
```shell
$ pip install mkdocs
```
To test documentation locally run `mkdocs serve` in the root directory, this should start a server locally to preview your changes.
```
```shell
$ mkdocs serve
INFO - Building documentation...
WARNING - Config value: 'theme'. Warning: The theme 'united' will be removed in an upcoming MkDocs release. See http://www.mkdocs.org/about/release-notes/ for more details

View File

@@ -1,13 +0,0 @@
### What version of Traefik are you using (`traefik version`)?
### What is your environment & configuration (arguments, toml...)?
### What did you do?
### What did you expect to see?
### What did you see instead?

58
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,58 @@
<!--
PLEASE READ THIS MESSAGE.
Please keep in mind that the GitHub issue tracker is not intended as a general support forum, but for reporting bugs and feature requests.
For other type of questions, consider using one of:
- the Traefik community Slack channel: https://traefik.herokuapp.com
- StackOverflow: https://stackoverflow.com/questions/tagged/traefik
HOW TO WRITE A GOOD ISSUE?
- if it's possible use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title must be short and descriptive.
- Explain the conditions which led you to write this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->
### Do you want to request a *feature* or report a *bug*?
### What did you do?
### What did you expect to see?
### What did you see instead?
### Output of `traefik version`: (_What version of Traefik are you using?_)
```
(paste your output here)
```
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
```toml
# (paste your configuration here)
```
<!--
Add more configuration information here.
-->
### If applicable, please paste the log output in debug mode (`--debug` switch)
```
(paste your output here)
```

23
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,23 @@
<!--
PLEASE READ THIS MESSAGE.
HOW TO WRITE A GOOD PULL REQUEST?
- Make it small.
- Do only one thing.
- Avoid re-formatting.
- Make sure the code builds.
- Make sure all tests pass.
- Add tests.
- Write useful descriptions and titles.
- Address review comments in terms of additional commits.
- Do not amend/squash existing ones unless the PR is trivial.
- Read the contributing guide: https://github.com/containous/traefik/blob/master/.github/CONTRIBUTING.md.
-->
### Description
<!--
Briefly describe the pull request in a few paragraphs.
-->

2
.github/cpr.sh vendored
View File

@@ -23,4 +23,4 @@ branch=$(curl -s https://api.github.com/repos/containous/traefik/pulls/$pr | jq
git remote add $remote git@github.com:$remote/traefik.git
git fetch $remote $branch
git checkout -t $remote/$branch
git checkout -t -b "$pr--$branch" $remote/$branch

2
.github/rmpr.sh vendored
View File

@@ -23,5 +23,5 @@ branch=$(curl -s https://api.github.com/repos/containous/traefik/pulls/$pr | jq
# clean
git checkout $initial
git branch -D $branch
git branch -D "$pr--$branch"
git remote remove $remote

2
.github/rpr.sh vendored
View File

@@ -33,4 +33,4 @@ trap clean EXIT
.github/cpr.sh $pr
git rebase $base
git push -f $remote $branch
git push --force-with-lease $remote "$pr--$branch"

12
.gitignore vendored
View File

@@ -1,15 +1,13 @@
/dist
gen.go
/autogen/gen.go
.idea
.intellij
*.iml
traefik
traefik.toml
*.test
vendor/
static/
/traefik
/traefik.toml
/static/
.vscode/
site/
/site/
*.log
*.exe
.DS_Store

11
.semaphoreci/setup.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
sudo -E apt-get -yq update
sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*
docker version
pip install --user -r requirements.txt
make pull-images
ci_retry make validate

6
.semaphoreci/tests.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
make test-unit
ci_retry make test-integration
make -j${N_MAKE_JOBS} crossbinary-default-parallel

39
.semaphoreci/vars Normal file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -e
export secure='btt4r13t09gQlHb6gYrvGC2yGCMMHfnp1Mz1RQedc4Mpf/FfT8aE6xmK2a2i9CCvskjrP0t/BFaS4yxIURjnFRn+ugQIEa0pLspB9UJArW/vgOSpIWM9/OQ/fg8z5XuMxN6Md4DL1/iLypMNSageA1x0TRdt89+D1N1dALpg5XRCXLFbC84TLi0gjlFuib9ibPKzEhLT+anCRJ6iZMzeupDSoaCVbAtJMoDvXw4+4AcRZ1+k4MybBLyCib5boaEOt4pTT88mz4Kk0YaMwPVJyg9Qv36VqyUcPS09Yd95LuyVQ4+tZt8Y1ccbIzULsK+sLM3hLCzxlmlpN3dQBlZJiiRtQde0mgGAKyC0P0A1XjuDTywcsa5edB+fTk1Dsewz9xZ9V0NmMz8t+UNZnaSsAPga9i86jULbXUUwMVSzVRc+Xgx02liB/8qI1xYC9FM6ilStt7rn7mF0k3KbiWhcptgeXjO6Lah9FjEKd5w4MXsdUSTi/86rQaLo+kj+XdaTrXCTulKHyRyQEUj+8V1w0oVz7pcGjePHd7y5oU9ByifVQy6sytuFBfRZvugM5bKHo+i0pcWvixrZS42DrzwxZJsspANOvqSe5ifVbvOkfUppQdCBIwptxV5N1b49XPKU3W/w34QJ8xGmKp3TFA7WwVCztriFHjPgiRpB3EG99Bg='
export REPO='containous/traefik'
if VERSION=$(git describe --exact-match --abbrev=0 --tags);
then
export VERSION
else
export VERSION=''
fi
export CODENAME=raclette
export N_MAKE_JOBS=2
function ci_retry {
local NRETRY=3
local NSLEEP=5
local n=0
until [ $n -ge $NRETRY ]
do
"$@" && break
n=$[$n+1]
echo "$@ failed, attempt ${n}/${NRETRY}"
sleep $NSLEEP
done
[ $n -lt $NRETRY ]
}
export -f ci_retry

View File

@@ -9,34 +9,25 @@ env:
- secure: btt4r13t09gQlHb6gYrvGC2yGCMMHfnp1Mz1RQedc4Mpf/FfT8aE6xmK2a2i9CCvskjrP0t/BFaS4yxIURjnFRn+ugQIEa0pLspB9UJArW/vgOSpIWM9/OQ/fg8z5XuMxN6Md4DL1/iLypMNSageA1x0TRdt89+D1N1dALpg5XRCXLFbC84TLi0gjlFuib9ibPKzEhLT+anCRJ6iZMzeupDSoaCVbAtJMoDvXw4+4AcRZ1+k4MybBLyCib5boaEOt4pTT88mz4Kk0YaMwPVJyg9Qv36VqyUcPS09Yd95LuyVQ4+tZt8Y1ccbIzULsK+sLM3hLCzxlmlpN3dQBlZJiiRtQde0mgGAKyC0P0A1XjuDTywcsa5edB+fTk1Dsewz9xZ9V0NmMz8t+UNZnaSsAPga9i86jULbXUUwMVSzVRc+Xgx02liB/8qI1xYC9FM6ilStt7rn7mF0k3KbiWhcptgeXjO6Lah9FjEKd5w4MXsdUSTi/86rQaLo+kj+XdaTrXCTulKHyRyQEUj+8V1w0oVz7pcGjePHd7y5oU9ByifVQy6sytuFBfRZvugM5bKHo+i0pcWvixrZS42DrzwxZJsspANOvqSe5ifVbvOkfUppQdCBIwptxV5N1b49XPKU3W/w34QJ8xGmKp3TFA7WwVCztriFHjPgiRpB3EG99Bg=
- REPO: $TRAVIS_REPO_SLUG
- VERSION: $TRAVIS_TAG
- CODENAME: morbier
- CODENAME: raclette
- N_MAKE_JOBS: 2
matrix:
fast_finish: true
include:
- env: DOCKER_VERSION=1.10.3
- env: DOCKER_VERSION=1.12.6
before_install:
- sudo -E apt-get -yq update
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-engine=${DOCKER_VERSION}*
install:
- docker version
- pip install --user -r requirements.txt
before_script:
- make validate
- make binary
script:
- travis_retry make test-unit
- travis_retry make test-integration
after_failure:
- docker ps
after_success:
- make crossbinary
- make image
- echo "Skipping tests... (Tests are executed on SemaphoreCI)"
before_deploy:
- mkdocs build --clean
- tar cfz dist/traefik-${VERSION}.src.tar.gz --exclude-vcs --exclude dist .
- >
if ! [ "$BEFORE_DEPLOY_RUN" ]; then
export BEFORE_DEPLOY_RUN=1;
sudo -E apt-get -yq update;
sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*;
docker version;
pip install --user -r requirements.txt;
make -j${N_MAKE_JOBS} crossbinary-parallel;
make image;
mkdocs build --clean;
tar cfz dist/traefik-${VERSION}.src.tar.gz --exclude-vcs --exclude dist .;
fi
deploy:
- provider: pages
edge: true

View File

@@ -1,5 +1,312 @@
# Change Log
## [v1.3.8](https://github.com/containous/traefik/tree/v1.3.8) (2017-09-07)
[All Commits](https://github.com/containous/traefik/compare/v1.3.7...v1.3.8)
**Bug fixes:**
- **[middleware]** Compress and websocket ([#2079](https://github.com/containous/traefik/pull/2079) by [ldez](https://github.com/ldez))
## [v1.3.7](https://github.com/containous/traefik/tree/v1.3.7) (2017-08-25)
[All Commits](https://github.com/containous/traefik/compare/v1.3.6...v1.3.7)
**Bug fixes:**
- **[oxy]** Only forward X-Forwarded-Port. ([#2007](https://github.com/containous/traefik/pull/2007) by [ldez](https://github.com/ldez))
## [v1.3.6](https://github.com/containous/traefik/tree/v1.3.6) (2017-08-20)
[All Commits](https://github.com/containous/traefik/compare/v1.3.5...v1.3.6)
**Bug fixes:**
- **[oxy,websocket]** Websocket parameters and protocol. ([#1970](https://github.com/containous/traefik/pull/1970) by [ldez](https://github.com/ldez))
## [v1.3.5](https://github.com/containous/traefik/tree/v1.3.5) (2017-08-01)
[All Commits](https://github.com/containous/traefik/compare/v1.3.4...v1.3.5)
**Bug fixes:**
- **[websocket]** Oxy with fixes on websocket + integration tests ([#1905](https://github.com/containous/traefik/pull/1905) by [Juliens](https://github.com/Juliens))
## [v1.3.4](https://github.com/containous/traefik/tree/v1.3.4) (2017-07-27)
[All Commits](https://github.com/containous/traefik/compare/v1.3.3...v1.3.4)
**Bug fixes:**
- **[middleware]** Double compression. ([#1863](https://github.com/containous/traefik/pull/1863) by [ldez](https://github.com/ldez))
- **[middleware]** Fix replace path rule ([#1859](https://github.com/containous/traefik/pull/1859) by [dedalusj](https://github.com/dedalusj))
- **[websocket]** New oxy with gorilla for websocket with integration tests ([#1896](https://github.com/containous/traefik/pull/1896) by [Juliens](https://github.com/Juliens))
## [v1.3.3](https://github.com/containous/traefik/tree/v1.3.3) (2017-07-06)
[All Commits](https://github.com/containous/traefik/compare/v1.3.2...v1.3.3)
**Bug fixes:**
- **[k8s]** Undo the Secrets controller sync wait. ([#1828](https://github.com/containous/traefik/pull/1828) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Tell glog to log everything into STDERR. ([#1817](https://github.com/containous/traefik/pull/1817) by [timoreimann](https://github.com/timoreimann))
## [v1.3.2](https://github.com/containous/traefik/tree/v1.3.2) (2017-06-29)
[All Commits](https://github.com/containous/traefik/compare/v1.3.1...v1.3.2)
**Bug fixes:**
- **[acme]** Add provided certificate checking before LE certificate generation with OnHostRule option ([#1772](https://github.com/containous/traefik/pull/1772) by [nmengin](https://github.com/nmengin))
- **[k8s]** Fix race on closing event channel. ([#1798](https://github.com/containous/traefik/pull/1798) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Upgrade go-marathon to dd6cbd4. ([#1800](https://github.com/containous/traefik/pull/1800) by [timoreimann](https://github.com/timoreimann))
- **[oxy,websocket]** Problem with keepalive when switching protocol failed ([#1782](https://github.com/containous/traefik/pull/1782) by [ldez](https://github.com/ldez))
- **[oxy]** Fix proxying of unannounced trailers ([#1805](https://github.com/containous/traefik/pull/1805) by [ldez](https://github.com/ldez))
## [v1.3.1](https://github.com/containous/traefik/tree/v1.3.1) (2017-06-16)
[All Commits](https://github.com/containous/traefik/compare/v1.3.0...v1.3.1)
**Enhancements:**
- **[logs,eureka,marathon]** Minor logs changes ([#1749](https://github.com/containous/traefik/pull/1749) by [ldez](https://github.com/ldez))
**Bug fixes:**
- **[k8s]** Use correct type when watching for k8s secrets ([#1700](https://github.com/containous/traefik/pull/1700) by [kekoav](https://github.com/kekoav))
- **[middleware]** fix: Double compression. ([#1714](https://github.com/containous/traefik/pull/1714) by [ldez](https://github.com/ldez))
- **[webui]** Don&#39;t fail when backend or frontend are empty. ([#1757](https://github.com/containous/traefik/pull/1757) by [ldez](https://github.com/ldez))
**Documentation:**
- **[k8s]** Fix capitalization of PathPrefixStrip in kubernetes doc ([#1695](https://github.com/containous/traefik/pull/1695) by [Miouge1](https://github.com/Miouge1))
## [v1.3.0](https://github.com/containous/traefik/tree/v1.3.0) (2017-05-31)
[All Commits](https://github.com/containous/traefik/compare/v1.2.0-rc1...v1.3.0)
**Enhancements:**
- **[acme]** Tighten regex match for wildcard certs [Addendum to #1018] ([#1227](https://github.com/containous/traefik/pull/1227) by [dtomcej](https://github.com/dtomcej))
- **[api,webui]** Feature web root path ([#1233](https://github.com/containous/traefik/pull/1233) by [tcoupin](https://github.com/tcoupin))
- **[authentication,docker,rancher]** Add Basic Auth per Frontend ([#1147](https://github.com/containous/traefik/pull/1147) by [SantoDE](https://github.com/SantoDE))
- **[authentication]** Allow usersFile to be specified for basic or digest auth ([#1189](https://github.com/containous/traefik/pull/1189) by [krancour](https://github.com/krancour))
- **[docker]** Allow multiple rules from docker labels containers with traefik.&lt;servicename&gt;.* properties ([#1257](https://github.com/containous/traefik/pull/1257) by [benoitf](https://github.com/benoitf))
- **[docker]** Use docker-compose labels for frontend and backend names ([#1235](https://github.com/containous/traefik/pull/1235) by [tcoupin](https://github.com/tcoupin))
- **[dynamodb]** add dynamodb backend ([#1158](https://github.com/containous/traefik/pull/1158) by [tskinn](https://github.com/tskinn))
- **[healthcheck,consul]** using more sensible consul blocking query to detect health check changes ([#1241](https://github.com/containous/traefik/pull/1241) by [vholovko](https://github.com/vholovko))
- **[healthcheck]** Add global health check interval parameter. ([#1338](https://github.com/containous/traefik/pull/1338) by [timoreimann](https://github.com/timoreimann))
- **[healthcheck]** Start health checks early. ([#1319](https://github.com/containous/traefik/pull/1319) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Upgrade k8s.io/client-go to version 2 ([#1178](https://github.com/containous/traefik/pull/1178) by [errm](https://github.com/errm))
- **[k8s]** Support cluster-external Kubernetes client. ([#1159](https://github.com/containous/traefik/pull/1159) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Add basic auth to kubernetes provider ([#1488](https://github.com/containous/traefik/pull/1488) by [alpe](https://github.com/alpe))
- **[k8s]** Adding support for Traefik to respect the K8s ingress class annotation ([#1182](https://github.com/containous/traefik/pull/1182) by [Regner](https://github.com/Regner))
- **[k8s]** Refactor k8s rule type annotation parsing/retrieval. ([#1151](https://github.com/containous/traefik/pull/1151) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Kubernetes support externalname service ([#1149](https://github.com/containous/traefik/pull/1149) by [Regner](https://github.com/Regner))
- **[kv]** Add libkv Username and Password ([#1357](https://github.com/containous/traefik/pull/1357) by [tcolgate](https://github.com/tcolgate))
- **[kv]** kv: Ignore backend servers with no url ([#1196](https://github.com/containous/traefik/pull/1196) by [klausenbusk](https://github.com/klausenbusk))
- **[logs]** New access logger ([#1408](https://github.com/containous/traefik/pull/1408) by [rjshep](https://github.com/rjshep))
- **[logs]** Revert &#34;New access logger&#34; ([#1541](https://github.com/containous/traefik/pull/1541) by [emilevauge](https://github.com/emilevauge))
- **[marathon]** Allow traefik.port to not be in the list of marathon ports ([#1394](https://github.com/containous/traefik/pull/1394) by [emilevauge](https://github.com/emilevauge))
- **[marathon]** Add tests lost during PR 1320. ([#1540](https://github.com/containous/traefik/pull/1540) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Make Traefik health checks label-configurable with Marathon. ([#1320](https://github.com/containous/traefik/pull/1320) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Detect proper hostname automatically. ([#1345](https://github.com/containous/traefik/pull/1345) by [diegooliveira](https://github.com/diegooliveira))
- **[rancher]** Added constraint management for Rancher provider ([#1527](https://github.com/containous/traefik/pull/1527) by [yyekhlef](https://github.com/yyekhlef))
- **[rancher]** Improve rancher provider handling of service and container health states ([#1343](https://github.com/containous/traefik/pull/1343) by [kelchm](https://github.com/kelchm))
- **[rancher]** Fix Rancher API pagination limits ([#1453](https://github.com/containous/traefik/pull/1453) by [martinbaillie](https://github.com/martinbaillie))
- **[rancher]** Fix Rancher backend left in uncommented state ([#1455](https://github.com/containous/traefik/pull/1455) by [martinbaillie](https://github.com/martinbaillie))
- **[rules]** Add Path Replacement Rule ([#1374](https://github.com/containous/traefik/pull/1374) by [ssttevee](https://github.com/ssttevee))
- **[rules]** Add PathStripRegex rule ([#1339](https://github.com/containous/traefik/pull/1339) by [seguins](https://github.com/seguins))
- **[webui]** Working UI ([#1542](https://github.com/containous/traefik/pull/1542) by [maxwo](https://github.com/maxwo))
- **[webui]** Dashboard filter ([#1437](https://github.com/containous/traefik/pull/1437) by [ldez](https://github.com/ldez))
- Upgrade dependencies. ([#1170](https://github.com/containous/traefik/pull/1170) by [timoreimann](https://github.com/timoreimann))
- Bump go 1.8 ([#1259](https://github.com/containous/traefik/pull/1259) by [emilevauge](https://github.com/emilevauge))
- Update TLS Ciphers for Go 1.8 ([#1276](https://github.com/containous/traefik/pull/1276) by [kekoav](https://github.com/kekoav))
- Add IdleConnTimeout to Traefik&#39;s http.server settings ([#1340](https://github.com/containous/traefik/pull/1340) by [bparli](https://github.com/bparli))
- Pass stripped prefix downstream as header ([#1442](https://github.com/containous/traefik/pull/1442) by [martinbaillie](https://github.com/martinbaillie))
- Extract some code in packages ([#1449](https://github.com/containous/traefik/pull/1449) by [vdemeester](https://github.com/vdemeester))
- Vendor generated file ([#1464](https://github.com/containous/traefik/pull/1464) by [vdemeester](https://github.com/vdemeester))
- Add unit tests for package safe ([#1517](https://github.com/containous/traefik/pull/1517) by [gottwald](https://github.com/gottwald))
- Use TOML-compatible duration type. ([#1350](https://github.com/containous/traefik/pull/1350) by [timoreimann](https://github.com/timoreimann))
- Get testify/require dependency. ([#1658](https://github.com/containous/traefik/pull/1658) by [timoreimann](https://github.com/timoreimann))
**Bug fixes:**
- **[consul]** fix consul sample endpoints ([#1303](https://github.com/containous/traefik/pull/1303) by [ruslansennov](https://github.com/ruslansennov))
- **[consul]** Fix Consul catalog prefix flags ([#1486](https://github.com/containous/traefik/pull/1486) by [emilevauge](https://github.com/emilevauge))
- **[docker]** Make port deterministic ([#1523](https://github.com/containous/traefik/pull/1523) by [tanyadegurechaff](https://github.com/tanyadegurechaff))
- **[k8s]** Remove rule type path list. ([#1630](https://github.com/containous/traefik/pull/1630) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Ignore Ingresses with empty Endpoint subsets. ([#1604](https://github.com/containous/traefik/pull/1604) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Ignore missing pass host header annotation. ([#1581](https://github.com/containous/traefik/pull/1581) by [timoreimann](https://github.com/timoreimann))
- **[logs]** Fix empty basic auth ([#1601](https://github.com/containous/traefik/pull/1601) by [emilevauge](https://github.com/emilevauge))
- **[logs]** Create log folder if not present ([#1507](https://github.com/containous/traefik/pull/1507) by [tanyadegurechaff](https://github.com/tanyadegurechaff))
- **[marathon]** Upgrade go-marathon to 15ea23e. ([#1635](https://github.com/containous/traefik/pull/1635) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Fix default timeouts for Marathon provider. ([#1398](https://github.com/containous/traefik/pull/1398) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Check for explicitly defined Marathon port first. ([#1474](https://github.com/containous/traefik/pull/1474) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Bump go-marathon dep ([#1524](https://github.com/containous/traefik/pull/1524) by [jangie](https://github.com/jangie))
- **[middleware,rules]** Fix behavior for PathPrefixStrip ([#1638](https://github.com/containous/traefik/pull/1638) by [seryl](https://github.com/seryl))
- **[middleware,websocket]** Fix stats hijack ([#1598](https://github.com/containous/traefik/pull/1598) by [emilevauge](https://github.com/emilevauge))
- **[provider]** Fix exported fields providers ([#1588](https://github.com/containous/traefik/pull/1588) by [emilevauge](https://github.com/emilevauge))
- **[rancher]** fix: Empty Rancher Service Labels. ([#1654](https://github.com/containous/traefik/pull/1654) by [ldez](https://github.com/ldez))
- **[sticky-session]** Maintain sticky flag on LB method validation failure. ([#1585](https://github.com/containous/traefik/pull/1585) by [timoreimann](https://github.com/timoreimann))
- Revert &#34;Vendor generated file&#34; ([#1534](https://github.com/containous/traefik/pull/1534) by [ldez](https://github.com/ldez))
- Update golang.org/x/sys to fix windows compilation ([#1448](https://github.com/containous/traefik/pull/1448) by [vdemeester](https://github.com/vdemeester))
- Fix systemd watchdog feature ([#1525](https://github.com/containous/traefik/pull/1525) by [guilhem](https://github.com/guilhem))
- Fixed ReplacePath rule executing out of order, when combined with PathPrefixStrip ([#1577](https://github.com/containous/traefik/pull/1577) by [aantono](https://github.com/aantono))
**Documentation:**
- **[cluster]** doc: Traefik cluster in beta. ([#1610](https://github.com/containous/traefik/pull/1610) by [ldez](https://github.com/ldez))
- **[docker]** Fix error in documentation for Docker labels ([#1179](https://github.com/containous/traefik/pull/1179) by [bgandon](https://github.com/bgandon))
- **[k8s]** Re Organise k8s docs to make 1.6 usage easier ([#1602](https://github.com/containous/traefik/pull/1602) by [errm](https://github.com/errm))
- **[k8s]** Add documentation for k8s RBAC configuration ([#1404](https://github.com/containous/traefik/pull/1404) by [aolwas](https://github.com/aolwas))
- **[k8s]** Add documentation about k8s Helm Chart ([#1367](https://github.com/containous/traefik/pull/1367) by [seguins](https://github.com/seguins))
- **[marathon]** Add Marathon guide. ([#1578](https://github.com/containous/traefik/pull/1578) by [Stibbons](https://github.com/Stibbons))
- **[metrics]** Fix prometheus metrics example ([#1157](https://github.com/containous/traefik/pull/1157) by [solidnerd](https://github.com/solidnerd))
- **[metrics]** Make toml Bucket array homogeneous ([#1369](https://github.com/containous/traefik/pull/1369) by [Starefossen](https://github.com/Starefossen))
- **[rancher]** make docs more clear about how to work with the current api ([#1337](https://github.com/containous/traefik/pull/1337) by [SantoDE](https://github.com/SantoDE))
- **[rules]** Motivate and explain regular expression rules. ([#1216](https://github.com/containous/traefik/pull/1216) by [timoreimann](https://github.com/timoreimann))
- **[rules]** Improve documentation for frontend rules. ([#1469](https://github.com/containous/traefik/pull/1469) by [timoreimann](https://github.com/timoreimann))
- License 2017, Træfɪk =&gt; Træfik ([#1368](https://github.com/containous/traefik/pull/1368) by [emilevauge](https://github.com/emilevauge))
- update wording ([#1458](https://github.com/containous/traefik/pull/1458) by [ben-st](https://github.com/ben-st))
- Fix typo in command line help. ([#1467](https://github.com/containous/traefik/pull/1467) by [mattcollier](https://github.com/mattcollier))
- Mention Traefik pronunciation in docs too. ([#1468](https://github.com/containous/traefik/pull/1468) by [timoreimann](https://github.com/timoreimann))
- Correct typo in code comment. ([#1473](https://github.com/containous/traefik/pull/1473) by [mattcollier](https://github.com/mattcollier))
- Change a word in the documentation ([#1274](https://github.com/containous/traefik/pull/1274) by [sroze](https://github.com/sroze))
- Add @trecloux to Maintainers ([#1226](https://github.com/containous/traefik/pull/1226) by [emilevauge](https://github.com/emilevauge))
- doc: enhance GitHub template. ([#1482](https://github.com/containous/traefik/pull/1482) by [ldez](https://github.com/ldez))
- Add @timoreimann to list of maintainers. ([#1215](https://github.com/containous/traefik/pull/1215) by [timoreimann](https://github.com/timoreimann))
- Add Traefik TOML sample section on how to bind to specific IP addr. ([#1194](https://github.com/containous/traefik/pull/1194) by [timoreimann](https://github.com/timoreimann))
- doc: enhance Github templates. ([#1515](https://github.com/containous/traefik/pull/1515) by [ldez](https://github.com/ldez))
- doc: small documentation review ([#1516](https://github.com/containous/traefik/pull/1516) by [ldez](https://github.com/ldez))
**Misc:**
- **[docker]** Few refactoring around the docker provider ([#1440](https://github.com/containous/traefik/pull/1440) by [vdemeester](https://github.com/vdemeester))
- **[k8s]** Updating Kubernetes tests to properly test missing endpoints code path ([#1436](https://github.com/containous/traefik/pull/1436) by [Regner](https://github.com/Regner))
- **[provider]** Extract providers to their own packages ([#1444](https://github.com/containous/traefik/pull/1444) by [vdemeester](https://github.com/vdemeester))
- Fix typo in server.go ([#1386](https://github.com/containous/traefik/pull/1386) by [mihaitodor](https://github.com/mihaitodor))
- Vendor dependencies ([#1144](https://github.com/containous/traefik/pull/1144) by [timoreimann](https://github.com/timoreimann))
- Prepare release v1.3.0-rc3 ([#1661](https://github.com/containous/traefik/pull/1661) by [ldez](https://github.com/ldez))
- Prepare release v1.3.0-rc2 ([#1606](https://github.com/containous/traefik/pull/1606) by [emilevauge](https://github.com/emilevauge))
- Prepare release v1.3.0-rc1 ([#1553](https://github.com/containous/traefik/pull/1553) by [emilevauge](https://github.com/emilevauge))
- Merge v1.2.3 master ([#1538](https://github.com/containous/traefik/pull/1538) by [emilevauge](https://github.com/emilevauge))
- Merge v1.2.1 master ([#1383](https://github.com/containous/traefik/pull/1383) by [emilevauge](https://github.com/emilevauge))
- Merge v1.2.0 rc2 master ([#1208](https://github.com/containous/traefik/pull/1208) by [emilevauge](https://github.com/emilevauge))
## [v1.3.0-rc3](https://github.com/containous/traefik/tree/v1.3.0-rc3) (2017-05-24)
[All Commits](https://github.com/containous/traefik/compare/v1.3.0-rc2...v1.3.0-rc3)
**Enhancements:**
- [#1658](https://github.com/containous/traefik/issues/1658) Get testify/require dependency. ([timoreimann](https://github.com/timoreimann))
**Bug fixes:**
- [#1507](https://github.com/containous/traefik/issues/1507) Create log folder if not present ([tanyadegurechaff](https://github.com/tanyadegurechaff))
- [#1604](https://github.com/containous/traefik/issues/1604) [k8s] Ignore Ingresses with empty Endpoint subsets. ([timoreimann](https://github.com/timoreimann))
- [#1630](https://github.com/containous/traefik/issues/1630) [k8s] Remove rule type path list. ([timoreimann](https://github.com/timoreimann))
- [#1635](https://github.com/containous/traefik/issues/1635) Upgrade go-marathon to 15ea23e. ([timoreimann](https://github.com/timoreimann))
- [#1638](https://github.com/containous/traefik/issues/1638) Fix behavior for PathPrefixStrip ([seryl](https://github.com/seryl))
- [#1654](https://github.com/containous/traefik/issues/1654) fix: Empty Rancher Service Labels. ([ldez](https://github.com/ldez))
**Documentation:**
- [#1578](https://github.com/containous/traefik/issues/1578) Add Marathon guide. ([Stibbons](https://github.com/Stibbons))
- [#1602](https://github.com/containous/traefik/issues/1602) Re Orginise k8s docs to make 1.6 usage easier ([errm](https://github.com/errm))
- [#1642](https://github.com/containous/traefik/issues/1642) Update changelog ([ldez](https://github.com/ldez))
## [v1.3.0-rc2](https://github.com/containous/traefik/tree/v1.3.0-rc2) (2017-05-16)
[All Commits](https://github.com/containous/traefik/compare/v1.3.0-rc1...v1.3.0-rc2)
**Enhancements:**
- Fixed ReplacePath rule executing out of order, when combined with PathPrefixStrip [#1577](https://github.com/containous/traefik/issues/1577) ([aantono](https://github.com/aantono))
**Bug fixes:**
- [Kubernetes] Ignore missing pass host header annotation. [#1581](https://github.com/containous/traefik/issues/1581) ([timoreimann](https://github.com/timoreimann))
- Maintain sticky flag on LB method validation failure. [#1585](https://github.com/containous/traefik/issues/1585) ([timoreimann](https://github.com/timoreimann))
- Fix exported fields providers [#1588](https://github.com/containous/traefik/issues/1588) ([emilevauge](https://github.com/emilevauge))
- Fix stats hijack [#1598](https://github.com/containous/traefik/issues/1598) ([emilevauge](https://github.com/emilevauge))
- Fix empty basic auth [#1601](https://github.com/containous/traefik/issues/1601) ([emilevauge](https://github.com/emilevauge))
**Documentation:**
- doc: Traefik cluster in beta. [#1610](https://github.com/containous/traefik/issues/1610) ([ldez](https://github.com/ldez))
## [v1.3.0-rc1](https://github.com/containous/traefik/tree/v1.3.0-rc1) (2017-05-05)
[All Commits](https://github.com/containous/traefik/compare/v1.2.0-rc1...v1.3.0-rc1)
**Enhancements:**
- Add Basic Auth per Frontend [#1147](https://github.com/containous/traefik/issues/1147) ([SantoDE](https://github.com/SantoDE))
- Kubernetes support externalname service [#1149](https://github.com/containous/traefik/issues/1149) ([Regner](https://github.com/Regner))
- add dynamodb backend [#1158](https://github.com/containous/traefik/issues/1158) ([tskinn](https://github.com/tskinn))
- Support cluster-external Kubernetes client. [#1159](https://github.com/containous/traefik/issues/1159) ([timoreimann](https://github.com/timoreimann))
- Add Traefik TOML sample section on how to bind to specific IP addr. [#1194](https://github.com/containous/traefik/issues/1194) ([timoreimann](https://github.com/timoreimann))
- kv: Ignore backend servers with no url [#1196](https://github.com/containous/traefik/issues/1196) ([klausenbusk](https://github.com/klausenbusk))
- Tighten regex match for wildcard certs [Addendum to #1018] [#1227](https://github.com/containous/traefik/issues/1227) ([dtomcej](https://github.com/dtomcej))
- Feature web root path [#1233](https://github.com/containous/traefik/issues/1233) ([tcoupin](https://github.com/tcoupin))
- using more sensible consul blocking query to detect health check changes [#1241](https://github.com/containous/traefik/issues/1241) ([vholovko](https://github.com/vholovko))
- Allow multiple rules from docker labels containers with traefik.&lt;servicename&gt;.* properties [#1257](https://github.com/containous/traefik/issues/1257) ([benoitf](https://github.com/benoitf))
- Update TLS Ciphers for Go 1.8 [#1276](https://github.com/containous/traefik/issues/1276) ([kekoav](https://github.com/kekoav))
- Start health checks early. [#1319](https://github.com/containous/traefik/issues/1319) ([timoreimann](https://github.com/timoreimann))
- Make Traefik health checks label-configurable with Marathon. [#1320](https://github.com/containous/traefik/issues/1320) ([timoreimann](https://github.com/timoreimann))
- Append template section asking for debug log output. [#1324](https://github.com/containous/traefik/issues/1324) ([timoreimann](https://github.com/timoreimann))
- Add global health check interval parameter. [#1338](https://github.com/containous/traefik/issues/1338) ([timoreimann](https://github.com/timoreimann))
- Fix regex with PathStrip [#1339](https://github.com/containous/traefik/issues/1339) ([seguins](https://github.com/seguins))
- Add IdleConnTimeout to Traefik&#39;s http.server settings [#1340](https://github.com/containous/traefik/issues/1340) ([bparli](https://github.com/bparli))
- Improve rancher provider handling of service and container health states [#1343](https://github.com/containous/traefik/issues/1343) ([kelchm](https://github.com/kelchm))
- [Marathon] Detect proper hostname automatically. [#1345](https://github.com/containous/traefik/issues/1345) ([diegooliveira](https://github.com/diegooliveira))
- Use TOML-compatible duration type. [#1350](https://github.com/containous/traefik/issues/1350) ([timoreimann](https://github.com/timoreimann))
- Add libkv Username and Password [#1357](https://github.com/containous/traefik/issues/1357) ([tcolgate](https://github.com/tcolgate))
- Make toml Bucket array homogeneous [#1369](https://github.com/containous/traefik/issues/1369) ([Starefossen](https://github.com/Starefossen))
- Add Path Replacement Rule [#1374](https://github.com/containous/traefik/issues/1374) ([ssttevee](https://github.com/ssttevee))
- New access logger [#1408](https://github.com/containous/traefik/issues/1408) ([rjshep](https://github.com/rjshep))
- feat(webui): Dashboard filter [#1437](https://github.com/containous/traefik/issues/1437) ([ldez](https://github.com/ldez))
- Pass stripped prefix downstream as header (#985) [#1442](https://github.com/containous/traefik/issues/1442) ([martinbaillie](https://github.com/martinbaillie))
- Extract some code in packages [#1449](https://github.com/containous/traefik/issues/1449) ([vdemeester](https://github.com/vdemeester))
- Fix Rancher API pagination limits [#1453](https://github.com/containous/traefik/issues/1453) ([martinbaillie](https://github.com/martinbaillie))
- Fix Rancher backend left in uncommented state [#1455](https://github.com/containous/traefik/issues/1455) ([martinbaillie](https://github.com/martinbaillie))
- Vendor generated file [#1464](https://github.com/containous/traefik/issues/1464) ([vdemeester](https://github.com/vdemeester))
- Add basic auth to kubernetes provider [#1488](https://github.com/containous/traefik/issues/1488) ([alpe](https://github.com/alpe))
- Add unit tests for package safe [#1517](https://github.com/containous/traefik/issues/1517) ([gottwald](https://github.com/gottwald))
- feat(rancher): added constraint management for rancher provider [#1527](https://github.com/containous/traefik/issues/1527) ([yyekhlef](https://github.com/yyekhlef))
- refactor: fix for PR with master branch. [#1537](https://github.com/containous/traefik/issues/1537) ([ldez](https://github.com/ldez))
- Add tests lost during PR 1320. [#1540](https://github.com/containous/traefik/issues/1540) ([timoreimann](https://github.com/timoreimann))
- Working UI [#1542](https://github.com/containous/traefik/issues/1542) ([maxwo](https://github.com/maxwo))
**Bug fixes:**
- Fix default timeouts for Marathon provider. [#1398](https://github.com/containous/traefik/issues/1398) ([timoreimann](https://github.com/timoreimann))
- Update golang.org/x/sys to fix windows compilation [#1448](https://github.com/containous/traefik/issues/1448) ([vdemeester](https://github.com/vdemeester))
- Check for explicitly defined Marathon port first. [#1474](https://github.com/containous/traefik/issues/1474) ([timoreimann](https://github.com/timoreimann))
- Fix Consul catalog prefix flags [#1486](https://github.com/containous/traefik/issues/1486) ([emilevauge](https://github.com/emilevauge))
- Move Docker test provider instantiation into t.Run body. [#1489](https://github.com/containous/traefik/issues/1489) ([timoreimann](https://github.com/timoreimann))
- Make port deterministic [#1523](https://github.com/containous/traefik/issues/1523) ([tanyadegurechaff](https://github.com/tanyadegurechaff))
- [Marathon] Bump go-marathon dep [#1524](https://github.com/containous/traefik/issues/1524) ([jangie](https://github.com/jangie))
- Fix systemd watchdog feature [#1525](https://github.com/containous/traefik/issues/1525) ([guilhem](https://github.com/guilhem))
- Revert &#34;Vendor generated file&#34; [#1534](https://github.com/containous/traefik/issues/1534) ([ldez](https://github.com/ldez))
**Documentation:**
- Fix prometheus metrics example [#1157](https://github.com/containous/traefik/issues/1157) ([solidnerd](https://github.com/solidnerd))
- Fix error in documentation for Docker labels [#1179](https://github.com/containous/traefik/issues/1179) ([bgandon](https://github.com/bgandon))
- Motivate and explain regular expression rules. [#1216](https://github.com/containous/traefik/issues/1216) ([timoreimann](https://github.com/timoreimann))
- Add @trecloux to Maintainers [#1226](https://github.com/containous/traefik/issues/1226) ([emilevauge](https://github.com/emilevauge))
- Change a word in the documentation [#1274](https://github.com/containous/traefik/issues/1274) ([sroze](https://github.com/sroze))
- make docs more clear about how to work with the current api [#1337](https://github.com/containous/traefik/issues/1337) ([SantoDE](https://github.com/SantoDE))
- Add documentation about k8s Helm Chart [#1367](https://github.com/containous/traefik/issues/1367) ([seguins](https://github.com/seguins))
- License 2017, Træfɪk =&gt; Træfik [#1368](https://github.com/containous/traefik/issues/1368) ([emilevauge](https://github.com/emilevauge))
- Add documentation for k8s RBAC configuration [#1404](https://github.com/containous/traefik/issues/1404) ([aolwas](https://github.com/aolwas))
- update wording [#1458](https://github.com/containous/traefik/issues/1458) ([ben-st](https://github.com/ben-st))
- Fix typo in command line help. [#1467](https://github.com/containous/traefik/issues/1467) ([mattcollier](https://github.com/mattcollier))
- Mention Traefik pronunciation in docs too. [#1468](https://github.com/containous/traefik/issues/1468) ([timoreimann](https://github.com/timoreimann))
- Improve documentation for frontend rules. [#1469](https://github.com/containous/traefik/issues/1469) ([timoreimann](https://github.com/timoreimann))
- Correct typo in code comment. [#1473](https://github.com/containous/traefik/issues/1473) ([mattcollier](https://github.com/mattcollier))
- doc: enhance GitHub template. [#1482](https://github.com/containous/traefik/issues/1482) ([ldez](https://github.com/ldez))
- doc: enhance Github templates. [#1515](https://github.com/containous/traefik/issues/1515) ([ldez](https://github.com/ldez))
- doc: small documentation review [#1516](https://github.com/containous/traefik/issues/1516) ([ldez](https://github.com/ldez))
**Misc:**
- Vendor dependencies [#1144](https://github.com/containous/traefik/issues/1144) ([timoreimann](https://github.com/timoreimann))
- Refactor k8s rule type annotation parsing/retrieval. [#1151](https://github.com/containous/traefik/issues/1151) ([timoreimann](https://github.com/timoreimann))
- Upgrade dependencies. [#1170](https://github.com/containous/traefik/issues/1170) ([timoreimann](https://github.com/timoreimann))
- Remove .gitattributes file. [#1172](https://github.com/containous/traefik/issues/1172) ([timoreimann](https://github.com/timoreimann))
- Upgrade k8s.io/client-go to version 2 [#1178](https://github.com/containous/traefik/issues/1178) ([errm](https://github.com/errm))
- Adding support for Traefik to respect the K8s ingress class annotation [#1182](https://github.com/containous/traefik/issues/1182) ([Regner](https://github.com/Regner))
- Allow usersFile to be specified for basic or digest auth [#1189](https://github.com/containous/traefik/issues/1189) ([krancour](https://github.com/krancour))
- Merge v1.2.0 rc2 master [#1208](https://github.com/containous/traefik/issues/1208) ([emilevauge](https://github.com/emilevauge))
- Add @timoreimann to list of maintainers. [#1215](https://github.com/containous/traefik/issues/1215) ([timoreimann](https://github.com/timoreimann))
- Use docker-compose labels for frontend and backend names [#1235](https://github.com/containous/traefik/issues/1235) ([tcoupin](https://github.com/tcoupin))
- Bump go 1.8 [#1259](https://github.com/containous/traefik/issues/1259) ([emilevauge](https://github.com/emilevauge))
- fix consul sample endpoints [#1303](https://github.com/containous/traefik/issues/1303) ([ruslansennov](https://github.com/ruslansennov))
- Merge v1.2.1 master [#1383](https://github.com/containous/traefik/issues/1383) ([emilevauge](https://github.com/emilevauge))
- Fix typo in server.go [#1386](https://github.com/containous/traefik/issues/1386) ([mihaitodor](https://github.com/mihaitodor))
- Allow traefik.port to not be in the list of marathon ports [#1394](https://github.com/containous/traefik/issues/1394) ([emilevauge](https://github.com/emilevauge))
- Updating Kubernetes tests to properly test missing endpoints code path [#1436](https://github.com/containous/traefik/issues/1436) ([Regner](https://github.com/Regner))
- Few refactoring around the docker provider [#1440](https://github.com/containous/traefik/issues/1440) ([vdemeester](https://github.com/vdemeester))
- Extract providers to their own packages [#1444](https://github.com/containous/traefik/issues/1444) ([vdemeester](https://github.com/vdemeester))
- Merge v1.2.3 master [#1538](https://github.com/containous/traefik/issues/1538) ([emilevauge](https://github.com/emilevauge))
- Revert &#34;First stage of access logging middleware. Initially without … [#1541](https://github.com/containous/traefik/issues/1541) ([emilevauge](https://github.com/emilevauge))
- Prepare release v1.3.0-rc1 [#1553](https://github.com/containous/traefik/issues/1553) ([emilevauge](https://github.com/emilevauge))
## [v1.2.3](https://github.com/containous/traefik/tree/v1.2.3) (2017-04-13)
[Full Changelog](https://github.com/containous/traefik/compare/v1.2.2...v1.2.3)
**Merged pull requests:**
- Fix too many redirect [\#1433](https://github.com/containous/traefik/pull/1433) ([emilevauge](https://github.com/emilevauge))
## [v1.2.2](https://github.com/containous/traefik/tree/v1.2.2) (2017-04-11)
[Full Changelog](https://github.com/containous/traefik/compare/v1.2.1...v1.2.2)
@@ -893,4 +1200,4 @@
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
\* *This Change Log was automatically generated by [gcg](https://github.com/ldez/gcg)*

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016 Containous SAS, Emile Vauge, emile@vauge.com
Copyright (c) 2016-2017 Containous SAS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -6,9 +6,10 @@ TRAEFIK_ENVS := \
-e TESTFLAGS \
-e VERBOSE \
-e VERSION \
-e CODENAME
-e CODENAME \
-e TESTDIRS
SRCS = $(shell git ls-files '*.go' | grep -v '^external/')
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/' | grep -v '^integration/vendor/')
BIND_DIR := "dist"
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)"
@@ -20,7 +21,10 @@ TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"containous/traefik")
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -v "/var/run/docker.sock:/var/run/docker.sock")
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) -it $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) -it $(DOCKER_RUN_OPTS)
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) -i $(DOCKER_RUN_OPTS)
print-%: ; @echo $*=$($*)
@@ -35,6 +39,24 @@ binary: generate-webui build ## build the linux binary
crossbinary: generate-webui build ## cross build the non-linux binaries
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate crossbinary
crossbinary-parallel:
$(MAKE) generate-webui
$(MAKE) build crossbinary-default crossbinary-others
crossbinary-default: generate-webui build
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-default
crossbinary-default-parallel:
$(MAKE) generate-webui
$(MAKE) build crossbinary-default
crossbinary-others: generate-webui build
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-others
crossbinary-others-parallel:
$(MAKE) generate-webui
$(MAKE) build crossbinary-others
test: build ## run the unit and integration tests
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration
@@ -42,10 +64,10 @@ test-unit: build ## run the unit tests
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit
test-integration: build ## run the integration tests
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-integration
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary test-integration
validate: build ## validate gofmt, golint and go vet
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-glide validate-gofmt validate-govet validate-golint validate-misspell
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-glide validate-gofmt validate-govet validate-golint validate-misspell validate-vendor
build: dist
docker build $(DOCKER_BUILD_ARGS) -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
@@ -59,7 +81,7 @@ build-no-cache: dist
shell: build ## start a shell inside the build env
$(DOCKER_RUN_TRAEFIK) /bin/bash
image: build ## build a docker traefik image
image: binary ## build a docker traefik image
docker build -t $(TRAEFIK_IMAGE) .
dist:
@@ -82,5 +104,11 @@ lint:
fmt:
gofmt -s -l -w $(SRCS)
pull-images:
for f in $(shell find ./integration/resources/compose/ -type f); do \
docker-compose -f $$f pull; \
done
help: ## this help
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

View File

@@ -1,6 +1,6 @@
<p align="center">
<img src="docs/img/traefik.logo.png" alt="Træfɪk" title="Træfɪk" />
<img src="docs/img/traefik.logo.png" alt="Træfik" title="Træfik" />
</p>
[![Build Status](https://travis-ci.org/containous/traefik.svg?branch=master)](https://travis-ci.org/containous/traefik)
@@ -12,8 +12,8 @@
[![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy)
Træfɪk (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
It supports several backends ([Docker](https://www.docker.com/), [Swarm](https://docs.docker.com/swarm), [Kubernetes](http://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Mesos](https://github.com/apache/mesos), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Zookeeper](https://zookeeper.apache.org), [BoltDB](https://github.com/boltdb/bolt), [Eureka](https://github.com/Netflix/eureka), Rest API, file...) to manage its configuration automatically and dynamically.
Træfik (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
It supports several backends ([Docker](https://www.docker.com/), [Swarm](https://docs.docker.com/swarm), [Kubernetes](http://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Mesos](https://github.com/apache/mesos), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Zookeeper](https://zookeeper.apache.org), [BoltDB](https://github.com/boltdb/bolt), [Eureka](https://github.com/Netflix/eureka), [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), Rest API, file...) to manage its configuration automatically and dynamically.
## Overview
@@ -28,11 +28,11 @@ But a microservices architecture is dynamic... Services are added, removed, kill
Traditional reverse-proxies are not natively dynamic. You can't change their configuration and hot-reload easily.
Here enters Træfɪk.
Here enters Træfik.
![Architecture](docs/img/architecture.png)
Træfɪk can listen to your service registry/orchestrator API, and knows each time a microservice is added, removed, killed or upgraded, and can generate its configuration automatically.
Træfik can listen to your service registry/orchestrator API, and knows each time a microservice is added, removed, killed or upgraded, and can generate its configuration automatically.
Routes to your services will be created instantly.
Run it and forget it!
@@ -64,21 +64,21 @@ Run it and forget it!
## Quickstart
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æfik 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 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 Kubernetes.
You will learn fundamental Træfik features and see some demos with Kubernetes.
[![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.
You will learn fundamental Træfik 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)
## Web UI
You can access to a simple HTML frontend of Træfik.
You can access the simple HTML frontend of Træfik.
![Web UI Providers](docs/img/web.frontend.png)
![Web UI Health](docs/img/traefik-health.png)
@@ -88,7 +88,6 @@ You can access to a simple HTML frontend of Træfik.
- [Oxy](https://github.com/vulcand/oxy): an awesome proxy library made by Mailgun guys
- [Gorilla mux](https://github.com/gorilla/mux): famous request router
- [Negroni](https://github.com/codegangsta/negroni): web middlewares made simple
- [Manners](https://github.com/mailgun/manners): graceful shutdown of http.Handler servers
- [Lego](https://github.com/xenolf/lego): the best [Let's Encrypt](https://letsencrypt.org) library in go
## Test it
@@ -128,33 +127,6 @@ Please note that this project is released with a [Contributor Code of Conduct](C
You can join [![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com) to get basic support.
If you prefer commercial support, please contact [containo.us](https://containo.us) by mail: <mailto:support@containo.us>.
## Træfɪk here and there
These projects use Træfɪk internally. If your company uses Træfɪk, we would be glad to get your feedback :) Contact us on [![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com)
- Project [Mantl](https://mantl.io/) from Cisco
![Web UI Providers](docs/img/mantl-logo.png)
> Mantl is a modern platform for rapidly deploying globally distributed services. A container orchestrator, docker, a network stack, something to pool your logs, something to monitor health, a sprinkle of service discovery and some automation.
- Project [Apollo](http://capgemini.github.io/devops/apollo/) from Cap Gemini
![Web UI Providers](docs/img/apollo-logo.png)
> Apollo is an open source project to aid with building and deploying IAAS and PAAS services. It is particularly geared towards managing containerized applications across multiple hosts, and big data type workloads. Apollo leverages other open source components to provide basic mechanisms for deployment, maintenance, and scaling of infrastructure and applications.
## Partners
[![Zenika](docs/img/zenika.logo.png)](https://zenika.com)
Zenika is one of the leading providers of professional Open Source services and agile methodologies in
Europe. We provide consulting, development, training and support for the worlds leading Open Source
software products.
[![Asteris](docs/img/asteris.logo.png)](https://aster.is)
Founded in 2014, Asteris creates next-generation infrastructure software for the modern datacenter. Asteris writes software that makes it easy for companies to implement continuous delivery and realtime data pipelines. We support the HashiCorp stack, along with Kubernetes, Apache Mesos, Spark and Kafka. We're core committers on mantl.io, consul-cli and mesos-consul.
## Maintainers
- Emile Vauge [@emilevauge](https://github.com/emilevauge)
@@ -163,7 +135,13 @@ Founded in 2014, Asteris creates next-generation infrastructure software for the
- Ed Robinson [@errm](https://github.com/errm)
- Daniel Tomcej [@dtomcej](https://github.com/dtomcej)
- Manuel Laufenberg [@SantoDE](https://github.com/SantoDE)
- Thomas Recloux [@trecloux](https://github.com/trecloux)
- Timo Reimann [@timoreimann](https://github.com/timoreimann)
## Credits
Kudos to [Peka](http://peka.byethost11.com/photoblog/) for his awesome work on the logo ![logo](docs/img/traefik.icon.png)
Kudos to [Peka](http://peka.byethost11.com/photoblog/) for his awesome work on the logo ![logo](docs/img/traefik.icon.png).
Traefik's logo licensed under the Creative Commons 3.0 Attributions license.
Traefik's logo was inspired by the gopher stickers made by Takuya Ueda (https://twitter.com/tenntenn).
The original Go gopher was designed by Renee French (http://reneefrench.blogspot.com/).

View File

@@ -328,14 +328,11 @@ func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, checkOnDemandDomain func
func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
domain := types.CanonicalDomain(clientHello.ServerName)
account := a.store.Get().(*Account)
//use regex to test for wildcard certs that might have been added into TLSConfig
for k := range a.TLSConfig.NameToCertificate {
selector := "^" + strings.Replace(k, "*.", ".*\\.?", -1) + "$"
match, _ := regexp.MatchString(selector, domain)
if match {
return a.TLSConfig.NameToCertificate[k], nil
}
if providedCertificate := a.getProvidedCertificate([]string{domain}); providedCertificate != nil {
return providedCertificate, nil
}
if challengeCert, ok := a.challengeProvider.getCertificate(domain); ok {
log.Debugf("ACME got challenge %s", domain)
return challengeCert, nil
@@ -520,8 +517,20 @@ func (a *ACME) loadCertificateOnDemand(clientHello *tls.ClientHelloInfo) (*tls.C
// LoadCertificateForDomains loads certificates from ACME for given domains
func (a *ACME) LoadCertificateForDomains(domains []string) {
a.jobs.In() <- func() {
log.Debugf("LoadCertificateForDomains %s...", domains)
log.Debugf("LoadCertificateForDomains %v...", domains)
if len(domains) == 0 {
// no domain
return
}
domains = fun.Map(types.CanonicalDomain, domains).([]string)
// Check provided certificates
if a.getProvidedCertificate(domains) != nil {
return
}
operation := func() error {
if a.client == nil {
return fmt.Errorf("ACME client still not built")
@@ -540,11 +549,7 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
}
account := a.store.Get().(*Account)
var domain Domain
if len(domains) == 0 {
// no domain
return
} else if len(domains) > 1 {
if len(domains) > 1 {
domain = Domain{Main: domains[0], SANs: domains[1:]}
} else {
domain = Domain{Main: domains[0]}
@@ -578,6 +583,29 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
}
}
// Get provided certificate which check a domains list (Main and SANs)
func (a *ACME) getProvidedCertificate(domains []string) *tls.Certificate {
// Use regex to test for provided certs that might have been added into TLSConfig
providedCertMatch := false
log.Debugf("Look for provided certificate to validate %s...", domains)
for k := range a.TLSConfig.NameToCertificate {
selector := "^" + strings.Replace(k, "*.", "[^\\.]*\\.?", -1) + "$"
for _, domainToCheck := range domains {
providedCertMatch, _ = regexp.MatchString(selector, domainToCheck)
if !providedCertMatch {
break
}
}
if providedCertMatch {
log.Debugf("Got provided certificate for domains %s", domains)
return a.TLSConfig.NameToCertificate[k]
}
}
log.Debugf("No provided certificate found for domains %s, get ACME certificate.", domains)
return nil
}
func (a *ACME) getDomainsCertificates(domains []string) (*Certificate, error) {
domains = fun.Map(types.CanonicalDomain, domains).([]string)
log.Debugf("Loading ACME certificates %s...", domains)

View File

@@ -1,6 +1,7 @@
package acme
import (
"crypto/tls"
"encoding/base64"
"net/http"
"net/http/httptest"
@@ -9,6 +10,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/xenolf/lego/acme"
)
@@ -277,3 +279,18 @@ cijFkALeQp/qyeXdFld2v9gUN3eCgljgcl0QweRoIc=---`)
t.Errorf("No change to acme.PreCheckDNS when meant to be adding enforcing override function.")
}
}
func TestAcme_getProvidedCertificate(t *testing.T) {
mm := make(map[string]*tls.Certificate)
mm["*.containo.us"] = &tls.Certificate{}
mm["traefik.acme.io"] = &tls.Certificate{}
a := ACME{TLSConfig: &tls.Config{NameToCertificate: mm}}
domains := []string{"traefik.containo.us", "trae.containo.us"}
certificate := a.getProvidedCertificate(domains)
assert.NotNil(t, certificate)
domains = []string{"traefik.acme.io", "trae.acme.io"}
certificate = a.getProvidedCertificate(domains)
assert.Nil(t, certificate)
}

View File

@@ -1,13 +1,21 @@
FROM golang:1.7
FROM golang:1.8
# Install a more recent version of mercurial to avoid mismatching results
# between glide run on a decently updated host system and the build container.
RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list && \
DEBIAN_FRONTEND=noninteractive apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -t jessie-backports --yes --no-install-recommends mercurial=3.9.1-1~bpo8+1 && \
rm -fr /var/lib/apt/lists/
RUN go get github.com/jteeuwen/go-bindata/... \
&& go get github.com/golang/lint/golint \
&& go get github.com/kisielk/errcheck \
&& go get github.com/client9/misspell/cmd/misspell \
&& go get github.com/mattfarina/glide-hash
&& go get github.com/mattfarina/glide-hash \
&& go get github.com/sgotti/glide-vc
# Which docker version to test on
ARG DOCKER_VERSION=1.10.3
ARG DOCKER_VERSION=17.03.1
# Which glide version to test on
@@ -20,17 +28,8 @@ RUN mkdir -p /usr/local/bin \
# Download docker
RUN mkdir -p /usr/local/bin \
&& curl -fL https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz \
&& curl -fL https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}-ce.tgz \
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
WORKDIR /go/src/github.com/containous/traefik
COPY glide.yaml glide.yaml
COPY glide.lock glide.lock
RUN glide install -v
COPY integration/glide.yaml integration/glide.yaml
COPY integration/glide.lock integration/glide.lock
RUN cd integration && glide install
COPY . /go/src/github.com/containous/traefik

View File

@@ -1,36 +0,0 @@
machine:
pre:
- sudo docker -d -e lxc -s btrfs -H tcp://0.0.0.0:2375:
background: true
- curl --retry 15 --retry-delay 3 -v http://172.17.42.1:2375/version
environment:
REPO: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
DOCKER_HOST: tcp://172.17.42.1:2375
MAKE_DOCKER_HOST: $DOCKER_HOST
VERSION: v1.0.alpha.$CIRCLE_BUILD_NUM
dependencies:
pre:
- docker version
- go get github.com/tcnksm/ghr
- make validate
override:
- make binary
test:
override:
- make test-unit
- make test-integration
post:
- make crossbinary
- make image
deployment:
hub:
branch: master
commands:
- ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME --prerelease ${VERSION} dist/
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker push ${REPO,,}:latest
- docker tag ${REPO,,}:latest ${REPO,,}:${VERSION}
- docker push ${REPO,,}:${VERSION}

View File

@@ -1,4 +1,4 @@
package cmd
package main
import (
"bytes"
@@ -16,28 +16,69 @@ import (
var (
bugtracker = "https://github.com/containous/traefik/issues/new"
bugTemplate = `### What version of Traefik are you using?
` + "```" + `
{{.Version}}
` + "```" + `
bugTemplate = `<!--
PLEASE READ THIS MESSAGE.
Please keep in mind that the GitHub issue tracker is not intended as a general support forum, but for reporting bugs and feature requests.
For other type of questions, consider using one of:
- the Traefik community Slack channel: https://traefik.herokuapp.com
- StackOverflow: https://stackoverflow.com/questions/tagged/traefik
HOW TO WRITE A GOOD ISSUE?
- if it's possible use the command` + "`" + `traefik bug` + "`" + `. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title must be short and descriptive.
- Explain the conditions which led you to write this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->
### Do you want to request a *feature* or report a *bug*?
### What is your environment & configuration (arguments, toml...)?
` + "```" + `
{{.Configuration}}
` + "```" + `
### What did you do?
### What did you expect to see?
### What did you see instead?
### Output of ` + "`" + `traefik version` + "`" + `: (_What version of Traefik are you using?_)
` + "```" + `
{{.Version}}
` + "```" + `
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
` + "```" + `toml
{{.Configuration}}
` + "```" + `
<!--
Add more configuration information here.
-->
### If applicable, please paste the log output in debug mode (` + "`" + `--debug` + "`" + ` switch)
` + "```" + `
(paste your output here)
` + "```" + `
`
)
// NewBugCmd builds a new Bug command
func NewBugCmd(traefikConfiguration interface{}, traefikPointersConfiguration interface{}) *flaeg.Command {
// newBugCmd builds a new Bug command
func newBugCmd(traefikConfiguration interface{}, traefikPointersConfiguration interface{}) *flaeg.Command {
//version Command init
return &flaeg.Command{
@@ -75,8 +116,8 @@ func NewBugCmd(traefikConfiguration interface{}, traefikPointersConfiguration in
}
body := bug.String()
url := bugtracker + "?body=" + url.QueryEscape(body)
if err := openBrowser(url); err != nil {
URL := bugtracker + "?body=" + url.QueryEscape(body)
if err := openBrowser(URL); err != nil {
fmt.Print("Please file a new issue at " + bugtracker + " using this template:\n\n")
fmt.Print(body)
}
@@ -89,15 +130,15 @@ func NewBugCmd(traefikConfiguration interface{}, traefikPointersConfiguration in
}
}
func openBrowser(url string) error {
func openBrowser(URL string) error {
var err error
switch runtime.GOOS {
case "linux":
err = exec.Command("xdg-open", url).Start()
err = exec.Command("xdg-open", URL).Start()
case "windows":
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", URL).Start()
case "darwin":
err = exec.Command("open", url).Start()
err = exec.Command("open", URL).Start()
default:
err = fmt.Errorf("unsupported platform")
}

313
cmd/traefik/traefik.go Normal file
View File

@@ -0,0 +1,313 @@
package main
import (
"crypto/tls"
"encoding/json"
"fmt"
fmtlog "log"
"net/http"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/containous/flaeg"
"github.com/containous/staert"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/server"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/coreos/go-systemd/daemon"
"github.com/docker/libkv/store"
"github.com/satori/go.uuid"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
//traefik config inits
traefikConfiguration := server.NewTraefikConfiguration()
traefikPointersConfiguration := server.NewTraefikDefaultPointersConfiguration()
//traefik Command init
traefikCmd := &flaeg.Command{
Name: "traefik",
Description: `traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
Complete documentation is available at https://traefik.io`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: func() error {
run(traefikConfiguration)
return nil
},
}
//storeconfig Command init
var kv *staert.KvSource
var err error
storeconfigCmd := &flaeg.Command{
Name: "storeconfig",
Description: `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: func() error {
if kv == nil {
return fmt.Errorf("Error using command storeconfig, no Key-value store defined")
}
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
if err != nil {
return err
}
fmtlog.Printf("Storing configuration: %s\n", jsonConf)
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
if err != nil {
return err
}
if traefikConfiguration.GlobalConfiguration.ACME != nil && len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
// convert ACME json file to KV store
store := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
object, err := store.Load()
if err != nil {
return err
}
meta := cluster.NewMetadata(object)
err = meta.Marshall()
if err != nil {
return err
}
source := staert.KvSource{
Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
}
err = source.StoreConfig(meta)
if err != nil {
return err
}
}
return nil
},
Metadata: map[string]string{
"parseAllSources": "true",
},
}
//init flaeg source
f := flaeg.New(traefikCmd, os.Args[1:])
//add custom parsers
f.AddParser(reflect.TypeOf(server.EntryPoints{}), &server.EntryPoints{})
f.AddParser(reflect.TypeOf(server.DefaultEntryPoints{}), &server.DefaultEntryPoints{})
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
f.AddParser(reflect.TypeOf([]acme.Domain{}), &acme.Domains{})
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
//add commands
f.AddCommand(newVersionCmd())
f.AddCommand(newBugCmd(traefikConfiguration, traefikPointersConfiguration))
f.AddCommand(storeconfigCmd)
usedCmd, err := f.GetCommand()
if err != nil {
fmtlog.Println(err)
os.Exit(-1)
}
if _, err := f.Parse(usedCmd); err != nil {
fmtlog.Printf("Error parsing command: %s\n", err)
os.Exit(-1)
}
//staert init
s := staert.NewStaert(traefikCmd)
//init toml source
toml := staert.NewTomlSource("traefik", []string{traefikConfiguration.ConfigFile, "/etc/traefik/", "$HOME/.traefik/", "."})
//add sources to staert
s.AddSource(toml)
s.AddSource(f)
if _, err := s.LoadConfig(); err != nil {
fmtlog.Println(fmt.Errorf("Error reading TOML config file %s : %s", toml.ConfigFileUsed(), err))
os.Exit(-1)
}
traefikConfiguration.ConfigFile = toml.ConfigFileUsed()
kv, err = CreateKvSource(traefikConfiguration)
if err != nil {
fmtlog.Printf("Error creating kv store: %s\n", err)
os.Exit(-1)
}
// IF a KV Store is enable and no sub-command called in args
if kv != nil && usedCmd == traefikCmd {
if traefikConfiguration.Cluster == nil {
traefikConfiguration.Cluster = &types.Cluster{Node: uuid.NewV4().String()}
}
if traefikConfiguration.Cluster.Store == nil {
traefikConfiguration.Cluster.Store = &types.Store{Prefix: kv.Prefix, Store: kv.Store}
}
s.AddSource(kv)
if _, err := s.LoadConfig(); err != nil {
fmtlog.Printf("Error loading configuration: %s\n", err)
os.Exit(-1)
}
}
if err := s.Run(); err != nil {
fmtlog.Printf("Error running traefik: %s\n", err)
os.Exit(-1)
}
os.Exit(0)
}
func run(traefikConfiguration *server.TraefikConfiguration) {
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
// load global configuration
globalConfiguration := traefikConfiguration.GlobalConfiguration
http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = globalConfiguration.MaxIdleConnsPerHost
if globalConfiguration.InsecureSkipVerify {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
loggerMiddleware := middlewares.NewLogger(globalConfiguration.AccessLogsFile)
defer loggerMiddleware.Close()
if globalConfiguration.File != nil && len(globalConfiguration.File.Filename) == 0 {
// no filename, setting to global config file
if len(traefikConfiguration.ConfigFile) != 0 {
globalConfiguration.File.Filename = traefikConfiguration.ConfigFile
} else {
log.Errorln("Error using file configuration backend, no filename defined")
}
}
if len(globalConfiguration.EntryPoints) == 0 {
globalConfiguration.EntryPoints = map[string]*server.EntryPoint{"http": {Address: ":80"}}
globalConfiguration.DefaultEntryPoints = []string{"http"}
}
if globalConfiguration.Debug {
globalConfiguration.LogLevel = "DEBUG"
}
// logging
level, err := logrus.ParseLevel(strings.ToLower(globalConfiguration.LogLevel))
if err != nil {
log.Error("Error getting level", err)
}
log.SetLevel(level)
if len(globalConfiguration.TraefikLogsFile) > 0 {
dir := filepath.Dir(globalConfiguration.TraefikLogsFile)
err := os.MkdirAll(dir, 0755)
if err != nil {
log.Errorf("Failed to create log path %s: %s", dir, err)
}
fi, err := os.OpenFile(globalConfiguration.TraefikLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
defer func() {
if err := fi.Close(); err != nil {
log.Error("Error closing file", err)
}
}()
if err != nil {
log.Error("Error opening file", err)
} else {
log.SetOutput(fi)
log.SetFormatter(&logrus.TextFormatter{DisableColors: true, FullTimestamp: true, DisableSorting: true})
}
} else {
log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true, DisableSorting: true})
}
jsonConf, _ := json.Marshal(globalConfiguration)
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 {
log.Infof("Using TOML configuration file %s", traefikConfiguration.ConfigFile)
}
log.Debugf("Global configuration loaded %s", string(jsonConf))
svr := server.NewServer(globalConfiguration)
svr.Start()
defer svr.Close()
sent, err := daemon.SdNotify(false, "READY=1")
if !sent && err != nil {
log.Error("Fail to notify", err)
}
t, err := daemon.SdWatchdogEnabled(false)
if err != nil {
log.Error("Problem with watchdog", err)
} else if t != 0 {
// Send a ping each half time given
t = t / 2
log.Info("Watchdog activated with timer each ", t)
safe.Go(func() {
tick := time.Tick(t)
for range tick {
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
log.Error("Fail to tick watchdog")
}
}
})
}
svr.Wait()
log.Info("Shutting down")
}
// CreateKvSource creates KvSource
// TLS support is enable for Consul and Etcd backends
func CreateKvSource(traefikConfiguration *server.TraefikConfiguration) (*staert.KvSource, error) {
var kv *staert.KvSource
var store store.Store
var err error
switch {
case traefikConfiguration.Consul != nil:
store, err = traefikConfiguration.Consul.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Consul.Prefix,
}
case traefikConfiguration.Etcd != nil:
store, err = traefikConfiguration.Etcd.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Etcd.Prefix,
}
case traefikConfiguration.Zookeeper != nil:
store, err = traefikConfiguration.Zookeeper.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Zookeeper.Prefix,
}
case traefikConfiguration.Boltdb != nil:
store, err = traefikConfiguration.Boltdb.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Boltdb.Prefix,
}
}
return kv, err
}

View File

@@ -1,4 +1,4 @@
package cmd
package main
import (
"fmt"
@@ -17,8 +17,8 @@ Go version: {{.GoVersion}}
Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}`
// NewVersionCmd builds a new Version command
func NewVersionCmd() *flaeg.Command {
// newVersionCmd builds a new Version command
func newVersionCmd() *flaeg.Command {
//version Command init
return &flaeg.Command{

10
docs.Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM alpine:3.7
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.local/bin
COPY requirements.txt /mkdocs/
WORKDIR /mkdocs
VOLUME /mkdocs
RUN apk --no-cache --no-progress add py-pip \
&& pip install --trusted-host pypi.python.org --user -r requirements.txt

View File

@@ -13,12 +13,12 @@ Let's take our example from the [overview](https://docs.traefik.io/#overview) ag
> ![Architecture](img/architecture.png)
Let's zoom on Træfɪk and have an overview of its internal architecture:
Let's zoom on Træfik and have an overview of its internal architecture:
![Architecture](img/internal.png)
- Incoming requests end on [entrypoints](#entrypoints), as the name suggests, they are the network entry points into Træfɪk (listening port, SSL, traffic redirection...).
- Incoming requests end on [entrypoints](#entrypoints), as the name suggests, they are the network entry points into Træfik (listening port, SSL, traffic redirection...).
- Traffic is then forwarded to a matching [frontend](#frontends). A frontend defines routes from [entrypoints](#entrypoints) to [backends](#backends).
Routes are created using requests fields (`Host`, `Path`, `Headers`...) and can match or not a request.
- The [frontend](#frontends) will then send the request to a [backend](#backends). A backend can be composed by one or more [servers](#servers), and by a load-balancing strategy.
@@ -26,7 +26,7 @@ Routes are created using requests fields (`Host`, `Path`, `Headers`...) and can
## Entrypoints
Entrypoints are the network entry points into Træfɪk.
Entrypoints are the network entry points into Træfik.
They can be defined using:
- a port (80, 443...)
@@ -73,25 +73,62 @@ And here is another example with client certificate authentication:
## Frontends
A frontend is a set of rules that forwards the incoming traffic from an entrypoint to a backend.
Frontends can be defined using the following rules:
A frontend consists of a set of rules that determine how incoming requests are forwarded from an entrypoint to a backend.
- `Headers: Content-Type, application/json`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched.
- `HeadersRegexp: Content-Type, application/(text|json)`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support.
- `Host: traefik.io, www.traefik.io`: Match request host with given host list.
- `HostRegexp: traefik.io, {subdomain:[a-z]+}.traefik.io`: Adds a matcher for the URL hosts. It accepts templates with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched.
- `Method: GET, POST, PUT`: Method adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched.
- `Path: /products/, /articles/{category}/{id:[0-9]+}`: Path adds a matcher for the URL paths. It accepts templates with zero or more URL variables enclosed by `{}`.
- `PathStrip`: Same as `Path` but strip the given prefix from the request URL's Path.
- `PathPrefix`: PathPrefix adds a matcher for the URL path prefixes. This matches if the given template is a prefix of the full URL path.
- `PathPrefixStrip`: Same as `PathPrefix` but strip the given prefix from the request URL's Path.
- `AddPrefix` : Add prefix from the request URL's Path.
Rules may be classified in one of two groups: Modifiers and matchers.
You can use multlple values for a rule by separating them with `,`.
You can use multiple rules by separating them by `;`.
### Modifiers
Modifier rules only modify the request. They do not have any impact on routing decisions being made.
Following is the list of existing modifier rules:
- `AddPrefix: /products`: Add path prefix to the existing request path prior to forwarding the request to the backend.
- `ReplacePath: /serverless-path`: Replaces the path and adds the old path to the `X-Replaced-Path` header. Useful for mapping to AWS Lambda or Google Cloud Functions.
### Matchers
Matcher rules determine if a particular request should be forwarded to a backend.
Separate multiple rule values by `,` (comma) in order to enable ANY semantics (i.e., forward a request if any rule matches). Does not work for `Headers` and `HeadersRegexp`.
Separate multiple rule values by `;` (semicolon) in order to enable ALL semantics (i.e., forward a request if all rules match).
You can optionally enable `passHostHeader` to forward client `Host` header to the backend.
Following is the list of existing matcher rules along with examples:
- `Headers: Content-Type, application/json`: Match HTTP header. It accepts a comma-separated key/value pair where both key and value must be literals.
- `HeadersRegexp: Content-Type, application/(text|json)`: Match HTTP header. It accepts a comma-separated key/value pair where the key must be a literal and the value may be a literal or a regular expression.
- `Host: traefik.io, www.traefik.io`: Match request host. It accepts a sequence of literal hosts.
- `HostRegexp: traefik.io, {subdomain:[a-z]+}.traefik.io`: Match request host. It accepts a sequence of literal and regular expression hosts.
- `Method: GET, POST, PUT`: Match request HTTP method. It accepts a sequence of HTTP methods.
- `Path: /products/, /articles/{category}/{id:[0-9]+}`: Match exact request path. It accepts a sequence of literal and regular expression paths.
- `PathStrip: /products/`: Match exact path and strip off the path prior to forwarding the request to the backend. It accepts a sequence of literal paths.
- `PathStripRegex: /articles/{category}/{id:[0-9]+}`: Match exact path and strip off the path prior to forwarding the request to the backend. It accepts a sequence of literal and regular expression paths.
- `PathPrefix: /products/, /articles/{category}/{id:[0-9]+}`: Match request prefix path. It accepts a sequence of literal and regular expression prefix paths.
- `PathPrefixStrip: /products/`: Match request prefix path and strip off the path prefix prior to forwarding the request to the backend. It accepts a sequence of literal prefix paths. Starting with Traefik 1.3, the stripped prefix path will be available in the `X-Forwarded-Prefix` header.
- `PathPrefixStripRegex: /articles/{category}/{id:[0-9]+}`: Match request prefix path and strip off the path prefix prior to forwarding the request to the backend. It accepts a sequence of literal and regular expression prefix paths. Starting with Traefik 1.3, the stripped prefix path will be available in the `X-Forwarded-Prefix` header.
In order to use regular expressions with Host and Path matchers, you must declare an arbitrarily named variable followed by the colon-separated regular expression, all enclosed in curly braces. Any pattern supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used. Example: `/posts/{id:[0-9]+}`.
(Note that the variable has no special meaning; however, it is required by the gorilla/mux dependency which embeds the regular expression and defines the syntax.)
#### Path Matcher Usage Guidelines
This section explains when to use the various path matchers.
Use `Path` if your backend listens on the exact path only. For instance, `Path: /products` would match `/products` but not `/products/shoes`.
Use a `*Prefix*` matcher if your backend listens on a particular base path but also serves requests on sub-paths. For instance, `PathPrefix: /products` would match `/products` but also `/products/shoes` and `/products/shirts`. Since the path is forwarded as-is, your backend is expected to listen on `/products`.
Use a `*Strip` matcher if your backend listens on the root path (`/`) but should be routeable on a specific prefix. For instance, `PathPrefixStrip: /products` would match `/products` but also `/products/shoes` and `/products/shirts`. Since the path is stripped prior to forwarding, your backend is expected to listen on `/`.
If your backend is serving assets (e.g., images or Javascript files), chances are it must return properly constructed relative URLs. Continuing on the example, the backend should return `/products/shoes/image.png` (and not `/images.png` which Traefik would likely not be able to associate with the same backend). The `X-Forwarded-Prefix` header (available since Traefik 1.3) can be queried to build such URLs dynamically.
Instead of distinguishing your backends by path only, you can add a Host matcher to the mix. That way, namespacing of your backends happens on the basis of hosts in addition to paths.
### Examples
Here is an example of frontends definition:
```toml
@@ -124,36 +161,55 @@ As seen in the previous example, you can combine multiple rules.
In TOML file, you can use multiple routes:
```toml
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost"
[frontends.frontend3.routes.test_2]
rule = "Path:/test"
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost"
[frontends.frontend3.routes.test_2]
rule = "Path:/test"
```
Here `frontend3` will forward the traffic to the `backend2` if the rules `Host:test3.localhost` **AND** `Path:/test` are matched.
You can also use the notation using a `;` separator, same result:
```toml
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost;Path:/test"
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost;Path:/test"
```
Finally, you can create a rule to bind multiple domains or Path to a frontend, using the `,` separator:
```toml
[frontends.frontend2]
[frontends.frontend2.routes.test_1]
rule = "Host:test1.localhost,test2.localhost"
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Path:/test1,/test2"
[frontends.frontend2]
[frontends.frontend2.routes.test_1]
rule = "Host:test1.localhost,test2.localhost"
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Path:/test1,/test2"
```
### Rules Order
When combining `Modifier` rules with `Matcher` rules, it is important to remember that `Modifier` rules **ALWAYS** apply after the `Matcher` rules.
The following rules are both `Matchers` and `Modifiers`, so the `Matcher` portion of the rule will apply first, and the `Modifier` will apply later.
- `PathStrip`
- `PathStripRegex`
- `PathPrefixStrip`
- `PathPrefixStripRegex`
`Modifiers` will be applied in a pre-determined order regardless of their order in the `rule` configuration section.
1. `PathStrip`
2. `PathPrefixStrip`
3. `PathStripRegex`
4. `PathPrefixStripRegex`
5. `AddPrefix`
6. `ReplacePath`
### Priorities
By default, routes will be sorted (in descending order) using rules length (to avoid path overlap):
@@ -161,20 +217,20 @@ By default, routes will be sorted (in descending order) using rules length (to a
You can customize priority by frontend:
```
[frontends]
[frontends.frontend1]
backend = "backend1"
priority = 10
passHostHeader = true
[frontends.frontend1.routes.test_1]
rule = "PathPrefix:/to"
[frontends.frontend2]
priority = 5
backend = "backend2"
passHostHeader = true
[frontends.frontend2.routes.test_1]
rule = "PathPrefix:/toto"
```toml
[frontends]
[frontends.frontend1]
backend = "backend1"
priority = 10
passHostHeader = true
[frontends.frontend1.routes.test_1]
rule = "PathPrefix:/to"
[frontends.frontend2]
priority = 5
backend = "backend2"
passHostHeader = true
[frontends.frontend2.routes.test_1]
rule = "PathPrefix:/toto"
```
Here, `frontend1` will be matched before `frontend2` (`10 > 5`).
@@ -290,17 +346,17 @@ Here is an example of backends and servers definition:
# Configuration
Træfɪk's configuration has two parts:
Træfik's configuration has two parts:
- The [static Træfɪk configuration](/basics#static-trfk-configuration) which is loaded only at the beginning.
- The [dynamic Træfɪk configuration](/basics#dynamic-trfk-configuration) which can be hot-reloaded (no need to restart the process).
- The [static Træfik configuration](/basics#static-trfk-configuration) which is loaded only at the beginning.
- The [dynamic Træfik configuration](/basics#dynamic-trfk-configuration) which can be hot-reloaded (no need to restart the process).
## Static Træfɪk configuration
## Static Træfik configuration
The static configuration is the global configuration which is setting up connections to configuration backends and entrypoints.
Træfɪk can be configured using many configuration sources with the following precedence order.
Træfik can be configured using many configuration sources with the following precedence order.
Each item takes precedence over the item below it:
- [Key-value Store](/basics/#key-value-stores)
@@ -312,7 +368,7 @@ It means that arguments override configuration file, and Key-value Store overrid
### Configuration file
By default, Træfɪk will try to find a `traefik.toml` in the following places:
By default, Træfik will try to find a `traefik.toml` in the following places:
- `/etc/traefik/`
- `$HOME/.traefik/`
@@ -338,7 +394,7 @@ Note that all default values will be displayed as well.
### Key-value stores
Træfɪk supports several Key-value stores:
Træfik supports several Key-value stores:
- [Consul](https://consul.io)
- [etcd](https://coreos.com/etcd/)
@@ -347,7 +403,7 @@ Træfɪk supports several Key-value stores:
Please refer to the [User Guide Key-value store configuration](/user-guide/kv-config/) section to get documentation on it.
## Dynamic Træfɪk configuration
## Dynamic Træfik configuration
The dynamic configuration concerns :
@@ -355,9 +411,9 @@ The dynamic configuration concerns :
- [Backends](/basics/#backends)
- [Servers](/basics/#servers)
Træfɪk can hot-reload those rules which could be provided by [multiple configuration backends](/toml/#configuration-backends).
Træfik can hot-reload those rules which could be provided by [multiple configuration backends](/toml/#configuration-backends).
We only need to enable `watch` option to make Træfɪk watch configuration backend changes and generate its configuration automatically.
We only need to enable `watch` option to make Træfik watch configuration backend changes and generate its configuration automatically.
Routes to services will be created and updated instantly at any changes.
Please refer to the [configuration backends](/toml/#configuration-backends) section to get documentation on it.
@@ -366,16 +422,16 @@ Please refer to the [configuration backends](/toml/#configuration-backends) sect
Usage: `traefik [command] [--flag=flag_argument]`
List of Træfɪk available commands with description :                                                             
List of Træfik available commands with description :                                                             
- `version` : Print version 
- `storeconfig` : Store the static traefik configuration into a Key-value stores. Please refer to the [Store Træfɪk configuration](/user-guide/kv-config/#store-trfk-configuration) section to get documentation on it.
- `storeconfig` : Store the static traefik configuration into a Key-value stores. Please refer to the [Store Træfik configuration](/user-guide/kv-config/#store-trfk-configuration) section to get documentation on it.
Each command may have related flags.
All those related flags will be displayed with :
```bash
$ traefik [command] --help
$ traefik [command] --help
```
Note that each command is described at the beginning of the help section:

View File

@@ -117,7 +117,7 @@ server {
Here is the `traefik.toml` file used:
```
```toml
MaxIdleConnsPerHost = 100000
defaultEntryPoints = ["http"]
@@ -145,7 +145,7 @@ defaultEntryPoints = ["http"]
## Results
### whoami:
```
```shell
wrk -t20 -c1000 -d60s -H "Host: test.traefik" --latency http://IP-whoami:80/bench
Running 1m test @ http://IP-whoami:80/bench
20 threads and 1000 connections
@@ -164,7 +164,7 @@ Transfer/sec: 6.40MB
```
### nginx:
```
```shell
wrk -t20 -c1000 -d60s -H "Host: test.traefik" --latency http://IP-nginx:8001/bench
Running 1m test @ http://IP-nginx:8001/bench
20 threads and 1000 connections
@@ -183,7 +183,7 @@ Transfer/sec: 4.97MB
```
### traefik:
```
```shell
wrk -t20 -c1000 -d60s -H "Host: test.traefik" --latency http://IP-traefik:8000/bench
Running 1m test @ http://IP-traefik:8000/bench
20 threads and 1000 connections

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 255 KiB

View File

@@ -1,5 +1,5 @@
<p align="center">
<img src="img/traefik.logo.png" alt="Træfɪk" title="Træfɪk" />
<img src="img/traefik.logo.png" alt="Træfik" title="Træfik" />
</p>
[![Build Status](https://travis-ci.org/containous/traefik.svg?branch=master)](https://travis-ci.org/containous/traefik)
@@ -10,8 +10,8 @@
[![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy)
Træfɪk is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
It supports several backends ([Docker](https://www.docker.com/), [Swarm](https://docs.docker.com/swarm), [Mesos/Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Zookeeper](https://zookeeper.apache.org), [BoltDB](https://github.com/boltdb/bolt), [Amazon ECS](https://aws.amazon.com/ecs/), Rest API, file...) to manage its configuration automatically and dynamically.
Træfik (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
It supports several backends ([Docker](https://www.docker.com/), [Swarm](https://docs.docker.com/swarm), [Mesos/Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Zookeeper](https://zookeeper.apache.org), [BoltDB](https://github.com/boltdb/bolt), [Amazon ECS](https://aws.amazon.com/ecs/), [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), Rest API, file...) to manage its configuration automatically and dynamically.
## Overview
@@ -26,11 +26,11 @@ But a microservices architecture is dynamic... Services are added, removed, kill
Traditional reverse-proxies are not natively dynamic. You can't change their configuration and hot-reload easily.
Here enters Træfɪk.
Here enters Træfik.
![Architecture](img/architecture.png)
Træfɪk can listen to your service registry/orchestrator API, and knows each time a microservice is added, removed, killed or upgraded, and can generate its configuration automatically.
Træfik can listen to your service registry/orchestrator API, and knows each time a microservice is added, removed, killed or upgraded, and can generate its configuration automatically.
Routes to your services will be created instantly.
Run it and forget it!
@@ -38,15 +38,15 @@ Run it and forget it!
## Quickstart
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æfik 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 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 Kubernetes.
You will learn fundamental Træfik features and see some demos with Kubernetes.
[![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.
You will learn fundamental Træfik 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)
@@ -70,7 +70,7 @@ docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.to
## Test it
You can test Træfɪk easily using [Docker compose](https://docs.docker.com/compose), with this `docker-compose.yml` file in a folder named `traefik`:
You can test Træfik easily using [Docker compose](https://docs.docker.com/compose), with this `docker-compose.yml` file in a folder named `traefik`:
```yaml
version: '2'
@@ -97,7 +97,7 @@ Start it from within the `traefik` folder:
docker-compose up -d
In a browser you may open `http://localhost:8080` to access Træfɪk's dashboard and observe the following magic.
In a browser you may open `http://localhost:8080` to access Træfik's dashboard and observe the following magic.
Now, create a folder named `test` and create a `docker-compose.yml` in it with this content:
@@ -121,14 +121,14 @@ networks:
Then, start and scale it in the `test` folder:
```
```shell
docker-compose up -d
docker-compose scale whoami=2
```
Finally, test load-balancing between the two services `test_whoami_1` and `test_whoami_2`:
```bash
```shell
$ curl -H Host:whoami.docker.localhost http://127.0.0.1
Hostname: ef194d07634a
IP: 127.0.0.1

View File

@@ -9,13 +9,15 @@
# Global configuration
################################################################
# Timeout in seconds.
# Duration to give active requests a chance to finish during hot-reloads
# Duration to give active requests a chance to finish during hot-reloads.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: 10
# Default: "10s"
#
# graceTimeOut = 10
# graceTimeOut = "10s"
# Enable debug mode
#
@@ -56,11 +58,24 @@
# Backends throttle duration: minimum duration in seconds between 2 events from providers
# before applying a new configuration. It avoids unnecessary reloads if multiples events
# are sent in a short amount of time.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: "2"
# Default: "2s"
#
# ProvidersThrottleDuration = "5"
# ProvidersThrottleDuration = "2s"
# IdleTimeout: maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.
# This is set to enforce closing of stale client connections.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming seconds.
#
# Optional
# Default: "180s"
#
# IdleTimeout = "360s"
# Controls the maximum idle (keep-alive) connections to keep per-host. If zero, DefaultMaxIdleConnsPerHost
# from the Go standard library net/http module is used.
@@ -90,9 +105,9 @@
### Constraints
In a micro-service architecture, with a central service discovery, setting constraints limits Træfɪk scope to a smaller number of routes.
In a micro-service architecture, with a central service discovery, setting constraints limits Træfik scope to a smaller number of routes.
Træfɪk filters services according to service attributes/tags set in your configuration backends.
Træfik filters services according to service attributes/tags set in your configuration backends.
Supported backends:
@@ -102,12 +117,13 @@ Supported backends:
- Zookeeper
- Etcd
- Consul Catalog
- Rancher
Supported filters:
- ```tag```
- `tag`
```
```toml
# Constraints definition
#
# Optional
@@ -193,20 +209,24 @@ Supported filters:
# To enable basic auth on an entrypoint
# with 2 user/pass: test:test and test2:test2
# Passwords can be encoded in MD5, SHA1 and BCrypt: you can use htpasswd to generate those ones
# Users can be specified directly in the toml file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence
# [entryPoints]
# [entryPoints.http]
# address = ":80"
# [entryPoints.http.auth.basic]
# users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
# usersFile = "/path/to/.htpasswd"
#
# To enable digest auth on an entrypoint
# with 2 user/realm/pass: test:traefik:test and test2:traefik:test2
# You can use htdigest to generate those ones
# Users can be specified directly in the toml file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence
# [entryPoints]
# [entryPoints.http]
# address = ":80"
# [entryPoints.http.auth.basic]
# users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
# usersFile = "/path/to/.htdigest"
#
# To specify an https entrypoint with a minimum TLS version, and specifying an array of cipher suites (from crypto/tls):
# [entryPoints]
@@ -250,6 +270,27 @@ Supported filters:
# attempts = 3
```
## Health check configuration
```toml
# Enable custom health check options.
#
# Optional
#
[healthcheck]
# Set the default health check interval. Will only be effective if health check
# paths are defined. Given provider-specific support, the value may be
# overridden on a per-backend basis.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: "30s"
#
# interval = "30s"
```
## ACME (Let's Encrypt) configuration
```toml
@@ -380,7 +421,7 @@ entryPoint = "https"
## File backend
Like any other reverse proxy, Træfɪk can be configured with a file. You have two choices:
Like any other reverse proxy, Træfik can be configured with a file. You have two choices:
- simply add your configuration at the end of the global configuration file `traefik.toml`:
@@ -514,7 +555,7 @@ filename = "rules.toml"
rule = "Path:/test"
```
If you want Træfɪk to watch file changes automatically, just add:
If you want Træfik to watch file changes automatically, just add:
```toml
[file]
@@ -530,6 +571,12 @@ To enable it:
[web]
address = ":8080"
# Set the root path for webui and API
#
# Optional
#
# path = "/mypath"
#
# SSL certificate and key used
#
# Optional
@@ -548,19 +595,22 @@ address = ":8080"
#
# To enable Traefik to export internal metrics to Prometheus
# [web.metrics.prometheus]
# Buckets=[0.1,0.3,1.2,5]
# Buckets=[0.1,0.3,1.2,5.0]
#
# To enable basic auth on the webui
# with 2 user/pass: test:test and test2:test2
# Passwords can be encoded in MD5, SHA1 and BCrypt: you can use htpasswd to generate those ones
# Users can be specified directly in the toml file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence
# [web.auth.basic]
# users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
# usersFile = "/path/to/.htpasswd"
# To enable digest auth on the webui
# with 2 user/realm/pass: test:traefik:test and test2:traefik:test2
# You can use htdigest to generate those ones
# Users can be specified directly in the toml file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence
# [web.auth.digest]
# users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
# usersFile = "/path/to/.htdigest"
```
- `/`: provides a simple HTML frontend of Træfik
@@ -570,7 +620,7 @@ address = ":8080"
- `/ping`: `GET` simple endpoint to check for Træfik process liveness.
```sh
```shell
$ curl -sv "http://localhost:8080/ping"
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
@@ -590,14 +640,14 @@ OK
- `/health`: `GET` json metrics
```sh
```shell
$ curl -s "http://localhost:8080/health" | jq .
{
// Træfɪk PID
// Træfik PID
"pid": 2458,
// Træfɪk server uptime (formated time)
// Træfik server uptime (formated time)
"uptime": "39m6.885931127s",
// Træfɪk server uptime in seconds
// Træfik server uptime in seconds
"uptime_sec": 2346.885931127,
// current server date
"time": "2015-10-07 18:32:24.362238909 +0200 CEST",
@@ -607,7 +657,7 @@ $ curl -s "http://localhost:8080/health" | jq .
"status_code_count": {
"502": 1
},
// count HTTP response status code since Træfɪk started
// count HTTP response status code since Træfik started
"total_status_code_count": {
"200": 7,
"404": 21,
@@ -649,7 +699,7 @@ $ curl -s "http://localhost:8080/health" | jq .
- `/api`: `GET` configuration for all providers
```sh
```shell
$ curl -s "http://localhost:8080/api" | jq .
{
"file": {
@@ -724,12 +774,12 @@ $ curl -s "http://localhost:8080/api" | jq .
- `/metrics`: You can enable Traefik to export internal metrics to different monitoring systems (Only Prometheus is supported at the moment).
```bash
$ traefik --web.metrics.prometheus --web.metrics.prometheus.buckets="0.1,0.3,1.2,5"
$ traefik --web.metrics.prometheus --web.metrics.prometheus.buckets="0.1,0.3,1.2,5.0"
```
## Docker backend
Træfɪk can be configured to use Docker as a backend configuration:
Træfik can be configured to use Docker as a backend configuration:
```toml
################################################################
@@ -801,7 +851,7 @@ swarmmode = false
Labels can be used on containers to override default behaviour:
- `traefik.backend=foo`: assign the container to `foo` backend
- `traefik.backend=foo`: give the name `backend-foo` to the generated backend for this container.
- `traefik.backend.maxconn.amount=10`: set a maximum number of connections to the backend. Must be used in conjunction with the below label to take effect.
- `traefik.backend.maxconn.extractorfunc=client.ip`: set the function to be used against the request to determine what to limit maximum connections to the backend by. Must be used in conjunction with the above label to take effect.
- `traefik.backend.loadbalancer.method=drr`: override the default `wrr` load balancer algorithm
@@ -811,18 +861,30 @@ Labels can be used on containers to override default behaviour:
- `traefik.port=80`: register this port. Useful when the container exposes multiples ports.
- `traefik.protocol=https`: override the default `http` protocol
- `traefik.weight=10`: assign this weight to the container
- `traefik.enable=false`: disable this container in Træfɪk
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
- `traefik.enable=false`: disable this container in Træfik
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`).
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
- `traefik.frontend.priority=10`: override default frontend priority
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
- `traefik.frontend.auth.basic=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0`: Sets a Basic Auth for that frontend with the users test:test and test2:test2
- `traefik.docker.network`: Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with docker inspect <container_id>) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name.
NB: when running inside a container, Træfɪk will need network access through `docker network connect <network> <traefik-container>`
If several ports need to be exposed from a container, the services labels can be used
- `traefik.<service-name>.port=443`: create a service binding with frontend/backend using this port. Overrides `traefik.port`.
- `traefik.<service-name>.protocol=https`: assign `https` protocol. Overrides `traefik.protocol`.
- `traefik.<service-name>.weight=10`: assign this service weight. Overrides `traefik.weight`.
- `traefik.<service-name>.frontend.backend=fooBackend`: assign this service frontend to `foobackend`. Default is to assign to the service backend.
- `traefik.<service-name>.frontend.entryPoints=http`: assign this service entrypoints. Overrides `traefik.frontend.entrypoints`.
- `traefik.<service-name>.frontend.auth.basic=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0` Sets a Basic Auth for that frontend with the users test:test and test2:test2.
- `traefik.<service-name>.frontend.passHostHeader=true`: Forward client `Host` header to the backend. Overrides `traefik.frontend.passHostHeader`.
- `traefik.<service-name>.frontend.priority=10`: assign the service frontend priority. Overrides `traefik.frontend.priority`.
- `traefik.<service-name>.frontend.rule=Path:/foo`: assign the service frontend rule. Overrides `traefik.frontend.rule`.
NB: when running inside a container, Træfik will need network access through `docker network connect <network> <traefik-container>`
## Marathon backend
Træfɪk can be configured to use Marathon as a backend configuration:
Træfik can be configured to use Marathon as a backend configuration:
```toml
@@ -910,19 +972,35 @@ domain = "marathon.localhost"
# dcosToken = "xxxxxx"
# Override DialerTimeout
# Amount of time in seconds to allow the Marathon provider to wait to open a TCP
# connection to a Marathon master
# Amount of time to allow the Marathon provider to wait to open a TCP connection
# to a Marathon master.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: 60
# dialerTimeout = 5
# Default: "60s"
# dialerTimeout = "60s"
# Set the TCP Keep Alive interval (in seconds) for the Marathon HTTP Client
# Set the TCP Keep Alive interval for the Marathon HTTP Client.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: 10
# Default: "10s"
#
# keepAlive = 10
# keepAlive = "10s"
# By default, a task's IP address (as returned by the Marathon API) is used as
# backend server if an IP-per-task configuration can be found; otherwise, the
# name of the host running the task is used.
# The latter behavior can be enforced by enabling this switch.
#
# Optional
# Default: false
#
# forceTaskHostname: false
```
Labels can be used on containers to override default behaviour:
@@ -933,11 +1011,13 @@ Labels can be used on containers to override default behaviour:
- `traefik.backend.loadbalancer.method=drr`: override the default `wrr` load balancer algorithm
- `traefik.backend.loadbalancer.sticky=true`: enable backend sticky sessions
- `traefik.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5`: create a [circuit breaker](/basics/#backends) to be used against the backend
- `traefik.backend.healthcheck.path=/health`: set the Traefik health check path [default: no health checks]
- `traefik.backend.healthcheck.interval=5s`: sets a custom health check interval in Go-parseable (`time.ParseDuration`) format [default: 30s]
- `traefik.portIndex=1`: register port by index in the application's ports array. Useful when the application exposes multiple ports.
- `traefik.port=80`: register the explicit application port value. Cannot be used alongside `traefik.portIndex`.
- `traefik.protocol=https`: override the default `http` protocol
- `traefik.weight=10`: assign this weight to the application
- `traefik.enable=false`: disable this application in Træfɪk
- `traefik.enable=false`: disable this application in Træfik
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
- `traefik.frontend.priority=10`: override default frontend priority
@@ -946,7 +1026,7 @@ Labels can be used on containers to override default behaviour:
## Mesos generic backend
Træfɪk can be configured to use Mesos as a backend configuration:
Træfik can be configured to use Mesos as a backend configuration:
```toml
@@ -1033,7 +1113,7 @@ domain = "mesos.localhost"
## Kubernetes Ingress backend
Træfɪk can be configured to use Kubernetes Ingress as a backend configuration:
Træfik can be configured to use Kubernetes Ingress as a backend configuration:
```toml
################################################################
@@ -1047,17 +1127,46 @@ Træfɪk can be configured to use Kubernetes Ingress as a backend configuration:
# Kubernetes server endpoint
#
# When deployed as a replication controller in Kubernetes,
# Traefik will use env variable KUBERNETES_SERVICE_HOST
# and KUBERNETES_SERVICE_PORT_HTTPS as endpoint
# When deployed as a replication controller in Kubernetes, Traefik will use
# the environment variables KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT
# to construct the endpoint.
# Secure token will be found in /var/run/secrets/kubernetes.io/serviceaccount/token
# and SSL CA cert in /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
#
# Optional
# The endpoint may be given to override the environment variable values.
#
# When the environment variables are not found, Traefik will try to connect to
# the Kubernetes API server with an external-cluster client. In this case, the
# endpoint is required. Specifically, it may be set to the URL used by
# `kubectl proxy` to connect to a Kubernetes cluster from localhost.
#
# Optional for in-cluster configuration, required otherwise
# Default: empty
#
# endpoint = "http://localhost:8080"
# namespaces = ["default","production"]
# Bearer token used for the Kubernetes client configuration.
#
# Optional
# Default: empty
#
# token = "my token"
# Path to the certificate authority file used for the Kubernetes client
# configuration.
#
# Optional
# Default: empty
#
# certAuthFilePath = "/my/ca.crt"
# Array of namespaces to watch.
#
# Optional
# Default: ["default"].
#
# namespaces = ["default", "production"]
# See: http://kubernetes.io/docs/user-guide/labels/#list-and-watch-filtering
# labelselector = "A and not B"
#
@@ -1078,9 +1187,25 @@ Additionally, an annotation can be used on Kubernetes services to set the [circu
- `traefik.backend.circuitbreaker: <expression>`: set the circuit breaker expression for the backend (Default: nil).
### Authentication
Is possible to add additional authentication annotations in the Ingress rule.
The source of the authentication is a secret that contains usernames and passwords inside the the key auth.
- `ingress.kubernetes.io/auth-type`: `basic`
- `ingress.kubernetes.io/auth-secret`: contains the usernames and passwords with access to the paths defined in the Ingress Rule.
The secret must be created in the same namespace as the Ingress rule.
Limitations:
- Basic authentication only.
- Realm not configurable; only `traefik` default.
- Secret must contain only single file.
## Consul backend
Træfɪk can be configured to use Consul as a backend configuration:
Træfik can be configured to use Consul as a backend configuration:
```toml
################################################################
@@ -1132,7 +1257,7 @@ Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-val
## Consul catalog backend
Træfɪk can be configured to use service discovery catalog of Consul as a backend configuration:
Træfik can be configured to use service discovery catalog of Consul as a backend configuration:
```toml
################################################################
@@ -1169,7 +1294,7 @@ used in consul.
Additional settings can be defined using Consul Catalog tags:
- `traefik.enable=false`: disable this container in Træfɪk
- `traefik.enable=false`: disable this container in Træfik
- `traefik.protocol=https`: override the default `http` protocol
- `traefik.backend.weight=10`: assign this weight to the container
- `traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5`
@@ -1183,7 +1308,7 @@ Additional settings can be defined using Consul Catalog tags:
## Etcd backend
Træfɪk can be configured to use Etcd as a backend configuration:
Træfik can be configured to use Etcd as a backend configuration:
```toml
################################################################
@@ -1220,6 +1345,13 @@ prefix = "/traefik"
#
# filename = "etcd.tmpl"
# Use etcd user/pass authentication
#
# Optional
#
# username = foo
# password = bar
# Enable etcd TLS connection
#
# Optional
@@ -1236,7 +1368,7 @@ Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-val
## Zookeeper backend
Træfɪk can be configured to use Zookeeper as a backend configuration:
Træfik can be configured to use Zookeeper as a backend configuration:
```toml
################################################################
@@ -1278,7 +1410,7 @@ Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-val
## BoltDB backend
Træfɪk can be configured to use BoltDB as a backend configuration:
Træfik can be configured to use BoltDB as a backend configuration:
```toml
################################################################
@@ -1318,7 +1450,7 @@ prefix = "/traefik"
## Eureka backend
Træfɪk can be configured to use Eureka as a backend configuration:
Træfik can be configured to use Eureka as a backend configuration:
```toml
@@ -1357,7 +1489,7 @@ Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-val
## ECS backend
Træfɪk can be configured to use Amazon ECS as a backend configuration:
Træfik can be configured to use Amazon ECS as a backend configuration:
```toml
@@ -1423,7 +1555,7 @@ Labels can be used on task containers to override default behaviour:
- `traefik.protocol=https`: override the default `http` protocol
- `traefik.weight=10`: assign this weight to the container
- `traefik.enable=false`: disable this container in Træfɪk
- `traefik.enable=false`: disable this container in Træfik
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
- `traefik.frontend.priority=10`: override default frontend priority
@@ -1435,7 +1567,7 @@ If `AccessKeyID`/`SecretAccessKey` is not given credentials will be resolved in
- Shared credentials, determined by `AWS_PROFILE` and `AWS_SHARED_CREDENTIALS_FILE`, defaults to `default` and `~/.aws/credentials`.
- EC2 instance role or ECS task role
Træfɪk needs the following policy to read ECS information:
Træfik needs the following policy to read ECS information:
```json
{
@@ -1461,7 +1593,7 @@ Træfɪk needs the following policy to read ECS information:
# Rancher backend
Træfɪk can be configured to use Rancher as a backend configuration:
Træfik can be configured to use Rancher as a backend configuration:
```toml
@@ -1489,6 +1621,12 @@ domain = "rancher.localhost"
#
Watch = true
# Polling interval (in seconds)
#
# Optional
#
RefreshSeconds = 15
# Expose Rancher services by default in traefik
#
# Optional
@@ -1496,34 +1634,111 @@ Watch = true
#
ExposedByDefault = false
# Endpoint to use when connecting to Rancher
# Filter services with unhealthy states and health states
#
# Optional
# Endpoint = "http://rancherserver.example.com"
# Default: false
#
EnableServiceHealthFilter = false
# Endpoint to use when connecting to Rancher
#
# Required
# Endpoint = "http://rancherserver.example.com/v1"
# AccessKey to use when connecting to Rancher
#
# Optional
# AccessKey = "XXXXXXXXX"
# Required
# AccessKey = "XXXXXXXXXXXXXXXXXXXX"
# SecretKey to use when connecting to Rancher
#
# Optional
# SecretKey = "XXXXXXXXXXX"
# Required
# SecretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
If you're deploying traefik as a service within rancher, you can alternatively set these labels on the service to let it only fetch data of its current environment. The settings `endpoint`, `accesskey` and `secretkey` can be omitted then.
As traefik needs access to the rancher API, you need to set the `endpoint`, `accesskey` and `secretkey` parameters.
- `io.rancher.container.create_agent=true`
- `io.rancher.container.agent.role=environment`
To enable traefik to fetch information about the Environment it's deployed in only, you need to create an `Environment API Key`. This can be found within the API Key advanced options.
Labels can be used on task containers to override default behaviour:
- `traefik.protocol=https`: override the default `http` protocol
- `traefik.weight=10`: assign this weight to the container
- `traefik.enable=false`: disable this container in Træfɪk
- `traefik.enable=false`: disable this container in Træfik
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
- `traefik.frontend.priority=10`: override default frontend priority
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
- `traefik.frontend.auth.basic=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0`: Sets a Basic Auth for that frontend with the users test:test and test2:test2
## DynamoDB backend
Træfik can be configured to use Amazon DynamoDB as a backend configuration:
```toml
################################################################
# DynamoDB configuration backend
################################################################
# Enable DynamoDB configuration backend
#
# Optional
#
[dynamodb]
# DyanmoDB Table Name
#
# Optional
#
TableName = "traefik"
# Enable watch DynamoDB changes
#
# Optional
#
Watch = true
# Polling interval (in seconds)
#
# Optional
#
RefreshSeconds = 15
# Region to use when connecting to AWS
#
# Required
#
# Region = "us-west-1"
# AccessKeyID to use when connecting to AWS
#
# Optional
#
# AccessKeyID = "abc"
# SecretAccessKey to use when connecting to AWS
#
# Optional
#
# SecretAccessKey = "123"
# Endpoint of local dynamodb instance for testing
#
# Optional
#
# Endpoint = "http://localhost:8080"
```
Items in the `dynamodb` table must have three attributes:
- `id` : string
- The id is the primary key.
- `name` : string
- The name is used as the name of the frontend or backend.
- `frontend` or `backend` : map
- This attribute's structure matches exactly the structure of a Frontend or Backend type in traefik. See `types/types.go` for details. The presence or absence of this attribute determines its type. So an item should never have both a `frontend` and a `backend` attribute.

View File

@@ -1,7 +1,7 @@
# Clustering / High Availability
# Clustering / High Availability (beta)
This guide explains how tu use Træfɪk in high availability mode.
In order to deploy and configure multiple Træfɪk instances, without copying the same configuration file on each instance, we will use a distributed Key-Value store.
This guide explains how tu use Træfik in high availability mode.
In order to deploy and configure multiple Træfik instances, without copying the same configuration file on each instance, we will use a distributed Key-Value store.
## Prerequisites
@@ -9,11 +9,12 @@ You will need a working KV store cluster.
## File configuration to KV store migration
We created a special Træfɪk command to help configuring your Key Value store from a Træfɪk TOML configuration file.
We created a special Træfik command to help configuring your Key Value store from a Træfik TOML configuration file.
Please refer to [this section](/user-guide/kv-config/#store-configuration-in-key-value-store) to get more details.
## Deploy a Træfɪk cluster
## Deploy a Træfik cluster
Once your Træfɪk configuration is uploaded on your KV store, you can start each Træfɪk instance.
A Træfɪk cluster is based on a master/slave model. When starting, Træfɪk will elect a master. If this instance fails, another master will be automatically elected.
Once your Træfik configuration is uploaded on your KV store, you can start each Træfik instance.
A Træfik cluster is based on a master/slave model.
When starting, Træfik will elect a master. If this instance fails, another master will be automatically elected.

View File

@@ -1,11 +1,11 @@
# Examples
You will find here some configuration examples of Træfɪk.
You will find here some configuration examples of Træfik.
## HTTP only
```
```toml
defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
@@ -14,7 +14,7 @@ defaultEntryPoints = ["http"]
## HTTP + HTTPS (with SNI)
```
```toml
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
@@ -33,7 +33,7 @@ Note that we can either give path to certificate file or directly the file conte
## HTTP redirect on HTTPS
```
```toml
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
@@ -50,7 +50,7 @@ defaultEntryPoints = ["http", "https"]
## Let's Encrypt support
```
```toml
[entryPoints]
[entryPoints.https]
address = ":443"
@@ -80,7 +80,7 @@ entryPoint = "https"
## Override entrypoints in frontends
```
```toml
[frontends]
[frontends.frontend1]
backend = "backend2"
@@ -107,7 +107,7 @@ With two user/pass:
Passwords are encoded in MD5: you can use htpasswd to generate those ones.
```
```toml
defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
@@ -121,7 +121,7 @@ defaultEntryPoints = ["http"]
Providing an authentication method as described above, it is possible to pass the user to the application
via a configurable header value
```
```toml
defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
@@ -130,4 +130,11 @@ defaultEntryPoints = ["http"]
headerField = "X-WebAuth-User"
[entryPoints.http.auth.basic]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
```
```
## Override the Traefik HTTP server IdleTimeout and/or throttle configurations from re-loading too quickly
```toml
IdleTimeout = "360s"
ProvidersThrottleDuration = "5s"
```

View File

@@ -1,6 +1,6 @@
# Kubernetes Ingress Controller
This guide explains how to use Træfɪk as an Ingress controller in a Kubernetes cluster.
This guide explains how to use Træfik as an Ingress controller in a Kubernetes cluster.
If you are not familiar with Ingresses in Kubernetes you might want to read the [Kubernetes user guide](http://kubernetes.io/docs/user-guide/ingress/)
The config files used in this guide can be found in the [examples directory](https://github.com/containous/traefik/tree/master/examples/k8s)
@@ -12,13 +12,76 @@ on your machine, as it is the quickest way to get a local Kubernetes cluster set
2. The `kubectl` binary should be [installed on your workstation](http://kubernetes.io/docs/getting-started-guides/minikube/#download-kubectl).
## Deploy Træfɪk
### Role Based Access Control configuration (Kubernetes 1.6+ only)
We are going to deploy Træfɪk with a
Kubernetes introduces [Role Based Access Control (RBAC)](https://kubernetes.io/docs/admin/authorization/rbac/) in 1.6+ to allow fine-grained control
of Kubernetes resources and api.
If your cluster is configured with RBAC, you may need to authorize Traefik to use
kubernetes API using ClusterRole and ClusterRoleBinding resources:
_Note: your cluster may have suitable ClusterRoles already setup, but the following should work everywhere_
```yaml
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- pods
- services
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
```
[examples/k8s/traefik-rbac.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/traefik-rbac.yaml)
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml
```
## Deploy Træfik using a Deployment object
We are going to deploy Træfik with a
[Deployment](http://kubernetes.io/docs/user-guide/deployments/), as this will
allow you to easily roll out config changes or update the image.
```yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
@@ -37,6 +100,7 @@ spec:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
containers:
- image: traefik
@@ -58,14 +122,14 @@ spec:
```
[examples/k8s/traefik.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/traefik.yaml)
> notice that we binding port 80 on the Træfɪk container to port 80 on the host.
> With a multi node cluster we might expose Træfɪk with a NodePort or LoadBalancer service
> and run more than 1 replica of Træfɪk for high availability.
> notice that we binding port 80 on the Træfik container to port 80 on the host.
> With a multi node cluster we might expose Træfik with a NodePort or LoadBalancer service
> and run more than 1 replica of Træfik for high availability.
To deploy Træfɪk to your cluster start by submitting the deployment to the cluster with `kubectl`:
To deploy Træfik to your cluster start by submitting the deployment to the cluster with `kubectl`:
```sh
kubectl apply -f examples/k8s/traefik.yaml
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik.yaml
```
### Check the deployment
@@ -74,7 +138,7 @@ Now lets check if our deployment was successful.
Start by listing the pods in the `kube-system` namespace:
```sh
```shell
$kubectl --namespace=kube-system get pods
NAME READY STATUS RESTARTS AGE
@@ -85,25 +149,37 @@ traefik-ingress-controller-678226159-eqseo 1/1 Running 0 7m
You should see that after submitting the Deployment to Kubernetes it has launched
a pod, and it is now running. _It might take a few moments for kubernetes to pull
the Træfɪk image and start the container._
the Træfik image and start the container._
> You could also check the deployment with the Kubernetes dashboard, run
> `minikube dashboard` to open it in your browser, then choose the `kube-system`
> namespace from the menu at the top right of the screen.
You should now be able to access Træfɪk on port 80 of your minikube instance.
You should now be able to access Træfik on port 80 of your minikube instance.
```sh
curl $(minikube ip)
404 page not found
```
> We expect to see a 404 response here as we haven't yet given Træfɪk any configuration.
> We expect to see a 404 response here as we haven't yet given Træfik any configuration.
## Deploy Træfik using Helm Chart
Instead of installing Træfik via a Deployment object, you can also use the Træfik Helm chart.
Install Træfik chart by:
```sh
helm install stable/traefik
```
For more information, check out [the doc](https://github.com/kubernetes/charts/tree/master/stable/traefik).
## Submitting An Ingress to the cluster.
Lets start by creating a Service and an Ingress that will expose the
[Træfɪk Web UI](https://github.com/containous/traefik#web-ui).
[Træfik Web UI](https://github.com/containous/traefik#web-ui).
```yaml
apiVersion: v1
@@ -123,6 +199,8 @@ kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: traefik-ui.local
@@ -134,8 +212,8 @@ spec:
```
[examples/k8s/ui.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/ui.yaml)
```sh
kubectl apply -f examples/k8s/ui.yaml
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/ui.yaml
```
Now lets setup an entry in our /etc/hosts file to route `traefik-ui.local`
@@ -145,11 +223,11 @@ to our cluster.
> You can get the ip address of your minikube instance by running `minikube ip`
```
```shell
echo "$(minikube ip) traefik-ui.local" | sudo tee -a /etc/hosts
```
We should now be able to visit [traefik-ui.local](http://traefik-ui.local) in the browser and view the Træfɪk Web UI.
We should now be able to visit [traefik-ui.local](http://traefik-ui.local) in the browser and view the Træfik Web UI.
## Name based routing
@@ -261,8 +339,8 @@ spec:
```
[examples/k8s/cheese-deployments.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheese-deployments.yaml)
```sh
kubectl apply -f examples/k8s/cheese-deployments.yaml
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheese-deployments.yaml
```
Next we need to setup a service for each of the cheese pods.
@@ -317,8 +395,8 @@ spec:
[examples/k8s/cheese-services.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheese-services.yaml)
```sh
kubectl apply -f examples/k8s/cheese-services.yaml
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheese-services.yaml
```
Now we can submit an ingress for the cheese websites.
@@ -328,6 +406,8 @@ apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheese
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: stilton.local
@@ -356,18 +436,18 @@ spec:
> Notice that we list each hostname, and add a backend service.
```sh
kubectl apply -f examples/k8s/cheese-ingress.yaml
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheese-ingress.yaml
```
Now visit the [Træfɪk dashboard](http://traefik-ui.local/) and you should
Now visit the [Træfik dashboard](http://traefik-ui.local/) and you should
see a frontend for each host. Along with a backend listing for each service
with a Server set up for each pod.
If you edit your `/etc/hosts` again you should be able to access the cheese
websites in your browser.
```sh
```shell
echo "$(minikube ip) stilton.local cheddar.local wensleydale.local" | sudo tee -a /etc/hosts
```
@@ -390,7 +470,8 @@ kind: Ingress
metadata:
name: cheeses
annotations:
traefik.frontend.rule.type: pathprefixstrip
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefixStrip
spec:
rules:
- host: cheeses.local
@@ -411,15 +492,15 @@ spec:
```
[examples/k8s/cheeses-ingress.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheeses-ingress.yaml)
> Notice that we are configuring Træfɪk to strip the prefix from the url path
> Notice that we are configuring Træfik to strip the prefix from the url path
> with the `traefik.frontend.rule.type` annotation so that we can use
> the containers from the previous example without modification.
```sh
kubectl apply -f examples/k8s/cheeses-ingress.yaml
```shell
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheeses-ingress.yaml
```
```sh
```shell
echo "$(minikube ip) cheeses.local" | sudo tee -a /etc/hosts
```
@@ -428,3 +509,72 @@ You should now be able to visit the websites in your browser.
* [cheeses.local/stilton](http://cheeses.local/stilton/)
* [cheeses.local/cheddar](http://cheeses.local/cheddar/)
* [cheeses.local/wensleydale](http://cheeses.local/wensleydale/)
## Disable passing the Host header
By default Træfik will pass the incoming Host header on to the upstream resource.
There are times however where you may not want this to be the case.
For example if your service is of the ExternalName type.
### Disable entirely
Add the following to your toml config:
```toml
disablePassHostHeaders = true
```
### Disable per ingress
To disable passing the Host header per ingress resource set the `traefik.frontend.passHostHeader`
annotation on your ingress to `false`.
Here is an example ingress definition:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.passHostHeader: "false"
spec:
rules:
- host: example.com
http:
paths:
- path: /static
backend:
serviceName: static
servicePort: https
```
And an example service definition:
```yaml
apiVersion: v1
kind: Service
metadata:
name: static
spec:
ports:
- name: https
port: 443
type: ExternalName
externalName: static.otherdomain.com
```
If you were to visit example.com/static the request would then be passed onto
static.otherdomain.com/static and static.otherdomain.com would receive the
request with the Host header being static.otherdomain.com.
Note: The per ingress annotation overides whatever the global value is set to.
So you could set `disablePassHostHeaders` to `true` in your toml file and then enable passing
the host header per ingress if you wanted.
## Excluding an ingress from Træfik
You can control which ingress Træfik cares about by using the `kubernetes.io/ingress.class` annotation.
By default if the annotation is not set at all Træfik will include the ingress.
If the annotation is set to anything other than traefik or a blank string Træfik will ignore it.
![](http://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -3,9 +3,9 @@
Both [static global configuration](/user-guide/kv-config/#static-configuration-in-key-value-store) and [dynamic](/user-guide/kv-config/#dynamic-configuration-in-key-value-store) configuration can be sorted in a Key-value store.
This section explains how to launch Træfɪk using a configuration loaded from a Key-value store.
This section explains how to launch Træfik using a configuration loaded from a Key-value store.
Træfɪk supports several Key-value stores:
Træfik supports several Key-value stores:
- [Consul](https://consul.io)
- [etcd](https://coreos.com/etcd/)
@@ -19,12 +19,12 @@ Note that we could do the same with any other Key-value Store.
## docker-compose file for Consul
The Træfɪk global configuration will be getted from a [Consul](https://consul.io) store.
The Træfik global configuration will be getted from a [Consul](https://consul.io) store.
First we have to launch Consul in a container.
The [docker-compose file](https://docs.docker.com/compose/compose-file/) allows us to launch Consul and four instances of the trivial app [emilevauge/whoamI](https://github.com/emilevauge/whoamI) :
```yml
```yaml
consul:
image: progrium/consul
command: -server -bootstrap -log-level debug -ui-dir /ui
@@ -54,11 +54,11 @@ whoami4:
## Upload the configuration in the Key-value store
We should now fill the store with the Træfɪk global configuration, as we do with a [TOML file configuration](/toml).
We should now fill the store with the Træfik global configuration, as we do with a [TOML file configuration](/toml).
To do that, we can send the Key-value pairs via [curl commands](https://www.consul.io/intro/getting-started/kv.html) or via the [Web UI](https://www.consul.io/intro/getting-started/ui.html).
Hopefully, Træfɪk allows automation of this process using the `storeconfig` subcommand.
Please refer to the [store Træfɪk configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
Fortunately, Træfik allows automation of this process using the `storeconfig` subcommand.
Please refer to the [store Træfik configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
Here is the toml configuration we would like to store in the Key-value Store :
@@ -112,21 +112,21 @@ And there, the same global configuration in the Key-value Store (using `prefix =
| `/traefik/consul/prefix` | `traefik` |
| `/traefik/web/address` | `:8081` |
In case you are setting key values manually,:
- Remember to specify the indexes (`0`,`1`, `2`, ... ) under prefixes `/traefik/defaultentrypoints/` and `/traefik/entrypoints/https/tls/certificates/` in order to match the global configuration structure.
- Be careful to give the correct IP address and port on the key `/traefik/consul/endpoint`.
In case you are setting key values manually:
- Remember to specify the indexes (`0`,`1`, `2`, ... ) under prefixes `/traefik/defaultentrypoints/` and `/traefik/entrypoints/https/tls/certificates/` in order to match the global configuration structure.
- Be careful to give the correct IP address and port on the key `/traefik/consul/endpoint`.
Note that we can either give path to certificate file or directly the file content itself.
## Launch Træfɪk
## Launch Træfik
We will now launch Træfɪk in a container.
We use CLI flags to setup the connection between Træfɪk and Consul.
We will now launch Træfik in a container.
We use CLI flags to setup the connection between Træfik and Consul.
All the rest of the global configuration is stored in Consul.
Here is the [docker-compose file](https://docs.docker.com/compose/compose-file/) :
```yml
```yaml
traefik:
image: traefik
command: --consul --consul.endpoint=127.0.0.1:8500
@@ -142,7 +142,7 @@ NB : Be careful to give the correct IP address and port in the flag `--consul.en
So far, only [Consul](https://consul.io) and [etcd](https://coreos.com/etcd/) support TLS connections.
To set it up, we should enable [consul security](https://www.consul.io/docs/internals/security.html) (or [etcd security](https://coreos.com/etcd/docs/latest/security.html)).
Then, we have to provide CA, Cert and Key to Træfɪk using `consul` flags :
Then, we have to provide CA, Cert and Key to Træfik using `consul` flags :
- `--consul.tls`
- `--consul.tls.ca=path/to/the/file`
@@ -161,9 +161,9 @@ Note that we can either give directly directly the file content itself (instead
Remember the command `traefik --help` to display the updated list of flags.
# Dynamic configuration in Key-value store
Following our example, we will provide backends/frontends rules to Træfɪk.
Following our example, we will provide backends/frontends rules to Træfik.
Note that this section is independent of the way Træfɪk got its static configuration.
Note that this section is independent of the way Træfik got its static configuration.
It means that the static configuration can either come from the same Key-value store or from any other sources.
## Key-value storage structure
@@ -259,13 +259,13 @@ And there, the same dynamic configuration in a KV Store (using `prefix = "traefi
## Atomic configuration changes
Træfɪk can watch the backends/frontends configuration changes and generate its configuration automatically.
Træfik can watch the backends/frontends configuration changes and generate its configuration automatically.
Note that only backends/frontends rules are dynamic, the rest of the Træfɪk configuration stay static.
Note that only backends/frontends rules are dynamic, the rest of the Træfik configuration stay static.
The [Etcd](https://github.com/coreos/etcd/issues/860) and [Consul](https://github.com/hashicorp/consul/issues/886) backends do not support updating multiple keys atomically. As a result, it may be possible for Træfɪk to read an intermediate configuration state despite judicious use of the `--providersThrottleDuration` flag. To solve this problem, Træfɪk supports a special key called `/traefik/alias`. If set, Træfɪk use the value as an alternative key prefix.
The [Etcd](https://github.com/coreos/etcd/issues/860) and [Consul](https://github.com/hashicorp/consul/issues/886) backends do not support updating multiple keys atomically. As a result, it may be possible for Træfik to read an intermediate configuration state despite judicious use of the `--providersThrottleDuration` flag. To solve this problem, Træfik supports a special key called `/traefik/alias`. If set, Træfik use the value as an alternative key prefix.
Given the key structure below, Træfɪk will use the `http://172.17.0.2:80` as its only backend (frontend keys have been omitted for brevity).
Given the key structure below, Træfik will use the `http://172.17.0.2:80` as its only backend (frontend keys have been omitted for brevity).
| Key | Value |
|-------------------------------------------------------------------------|-----------------------------|
@@ -297,24 +297,24 @@ Once the `/traefik/alias` key is updated, the new `/traefik_configurations/2` co
| `/traefik_configurations/2/backends/backend1/servers/server2/url` | `http://172.17.0.4:80` |
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
Note that Træfɪk *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik/alias`.
Note that Træfik *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik/alias`.
Further, if the `/traefik/alias` key is set, all other configuration with `/traefik/backends` or `/traefik/frontends` prefix are ignored.
# Store configuration in Key-value store
Don't forget to [setup the connection between Træfɪk and Key-value store](/user-guide/kv-config/#launch-trfk).
The static Træfɪk configuration in a key-value store can be automatically created and updated, using the [`storeconfig` subcommand](/basics/#commands).
Don't forget to [setup the connection between Træfik and Key-value store](/user-guide/kv-config/#launch-trfk).
The static Træfik configuration in a key-value store can be automatically created and updated, using the [`storeconfig` subcommand](/basics/#commands).
```bash
$ traefik storeconfig [flags] ...
$ traefik storeconfig [flags] ...
```
This command is here only to automate the [process which upload the configuration into the Key-value store](/user-guide/kv-config/#upload-the-configuration-in-the-key-value-store).
Træfɪk will not start but the [static configuration](/basics/#static-trfk-configuration) will be uploaded into the Key-value store.
Træfik will not start but the [static configuration](/basics/#static-trfk-configuration) will be uploaded into the Key-value store.
If you configured ACME (Let's Encrypt), your registration account and your certificates will also be uploaded.
To upload your ACME certificates to the KV store, get your traefik TOML file and add the new `storage` option in the `acme` section:
```
```toml
[acme]
email = "test@traefik.io"
storage = "traefik/acme/account" # the key where to store your certificates in the KV store
@@ -323,6 +323,7 @@ storageFile = "acme.json" # your old certificates store
Call `traefik storeconfig` to upload your config in the KV store.
Then remove the line `storageFile = "acme.json"` from your TOML config file.
That's it!
![](http://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -0,0 +1,96 @@
# Marathon
This guide explains how to integrate Marathon and operate the cluster in a reliable way from Traefik's standpoint.
# Host detection
Marathon offers multiple ways to run (Docker-containerized) applications, the most popular ones being
- BRIDGE-networked containers with dynamic high ports exposed
- HOST-networked containers with host machine ports
- containers with dedicated IP addresses ([IP-per-task](https://mesosphere.github.io/marathon/docs/ip-per-task.html)).
Traefik tries to detect the configured mode and route traffic to the right IP addresses. It is possible to force using task hosts with the `forceTaskHostname` option.
Given the complexity of the subject, it is possible that the heuristic fails. Apart from filing an issue and waiting for the feature request / bug report to get addressed, one workaround for such situations is to customize the Marathon template file to the individual needs. (Note that this does _not_ require rebuilding Traefik but only to point the `filename` configuration parameter to a customized version of the `marathon.tmpl` file on Traefik startup.)
# Port detection
Traefik also attempts to determine the right port (which is a [non-trivial matter in Marathon](https://mesosphere.github.io/marathon/docs/ports.html)). Following is the order by which Traefik tries to identify the port (the first one that yields a positive result will be used):
1. A arbitrary port specified through the `traefik.port` label.
1. The task port (possibly indexed through the `traefik.portIndex` label, otherwise the first one).
1. The port from the application's `portDefinitions` field (possibly indexed through the `traefik.portIndex` label, otherwise the first one).
1. The port from the application's `ipAddressPerTask` field (possibly indexed through the `traefik.portIndex` label, otherwise the first one).
# Achieving high availability
## Scenarios
There are three scenarios where the availability of a Marathon application could be impaired along with the risk of losing or failing requests:
- During the startup phase when Traefik already routes requests to the backend even though it has not completed its bootstrapping process yet.
- During the shutdown phase when Traefik still routes requests to the backend while the backend is already terminating.
- During a failure of the application when Traefik has not yet identified the backend as being erroneous.
The first two scenarios are common with every rolling upgrade of an application (i.e., a new version release or configuration update).
The following sub-sections describe how to resolve or mitigate each scenario.
### Startup
In general, it is possible to define [readiness checks](https://mesosphere.github.io/marathon/docs/readiness-checks.html) (available since Marathon version 1.1) per application and have Marathon take these into account during the startup phase. The idea is that each application provides an HTTP endpoint that Marathon queries periodically during an ongoing deployment in order to mark the associated readiness check result as successful if and only if the endpoint returns a response within the configured HTTP code range. As long as the check keeps failing, Marathon will not proceed with the deployment (within the configured upgrade stategy bounds).
Unfortunately, Traefik does not respect the result of the readiness check yet. Support is expected to land in a not-too-distant future release of Traefik, however, as being tracked by [issue 1559](https://github.com/containous/traefik/issues/1559).
A current mitigation strategy is to enable [retries](http://docs.traefik.io/toml/#retry-configuration) and make sure that a sufficient number of healthy application tasks exist so that one retry will likely hit one of those. Apart from its probabilistic nature, the workaround comes at the price of increased latency.
### Shutdown
It is possible to install a [termination handler](https://mesosphere.github.io/marathon/docs/health-checks.html) (available since Marathon version 1.3) with each application whose responsibility it is to delay the shutdown process long enough until the backend has been taken out of load-balancing rotation with reasonable confidence (i.e., Traefik has received an update from the Marathon event bus, recomputes the available Marathon backends, and applies the new configuration). Specifically, each termination handler should install a signal handler listening for a SIGTERM signal and implement the following steps on signal reception:
1. Disable Keep-Alive HTTP connections.
1. Keep accepting HTTP requests for a certain period of time.
1. Stop accepting new connections.
1. Finish serving any in-flight requests.
1. Shut down.
Traefik already ignores Marathon tasks whose state does not match `TASK_RUNNING`; since terminating tasks transition into the `TASK_KILLING` and eventually `TASK_KILLED` state, there is nothing further that needs to be done on Traefik's end.
How long HTTP requests should continue to be accepted in step 2 depends on how long Traefik needs to receive and process the Marathon configuration update. Under regular operational conditions, it should be on the order of seconds, with 10 seconds possibly being a good default value.
Again, configuring Traefik to do retries (as discussed in the previous section) can serve as a decent workaround strategy. Paired with termination handlers, they would cover for those cases where either the termination sequence or Traefik cannot complete their part of the orchestration process in time.
### Failure
A failing application always happens unexpectedly, and hence, it is very difficult or even impossible to rule out the adversal effects categorically. Failure reasons vary broadly and could stretch from unacceptable slowness, a task crash, or a network split.
There are two mitigaton efforts:
1. Configure [Marathon health checks](https://mesosphere.github.io/marathon/docs/health-checks.html) on each application.
1. Configure Traefik health checks (possibly via the `traefik.backend.healthcheck.*` labels) and make sure they probe with proper frequency.
The Marathon health check makes sure that applications once deemed dysfunctional are being rescheduled to different slaves. However, they might take a while to get triggered and the follow-up processes to complete. For that reason, the Treafik health check provides an additional check that responds more rapidly and does not require a configuration reload to happen. Additionally, it protects from cases that the Marathon health check may not be able to cover, such as a network split.
## (Non-)Alternatives
There are a few alternatives of varying quality that are frequently asked for. The remaining section is going to explore them along with a benefit/cost trade-off.
### Reusing Marathon health checks
It may seem obvious to reuse the Marathon health checks as a signal to Traefik whether an application should be taken into load-balancing rotation or not.
Apart from the increased latency a failing health check may have, a major problem with this is is that Marathon does not persist the health check results. Consequently, if a master re-election occurs in the Marathon clusters, all health check results will revert to the _unknown_ state, effectively causing all applications inside the cluster to become unavailable and leading to a complete cluster failure. Re-elections do not only happen during regular maintenance work (often requiring rolling upgrades of the Marathon nodes) but also when the Marathon leader fails spontaneously). As such, there is no way to handle this situation deterministically.
Finally, Marathon health checks are not mandatory (the default is to use the task state as reported by Mesos), so requiring them for Traefik would raise the entry barrier for Marathon users.
Traefik used to use the health check results but moved away from it as [users reported the dramatic consequences](https://github.com/containous/traefik/issues/653).
### Draining
Another common approach is to let a proxy drain backends that are supposed to shut down. That is, once a backend is supposed to shut down, Traefik would stop forwarding requests.
On the plus side, this would not require any modifications to the application in question. However, implementing this fully within Traefik seems like a non-trivial undertaking. Additionally, the approach is less flexible compared to a custom termination handler since only the latter allows for the implementation of custom termination sequences that go beyond simple request draining (e.g., persisting a snapshot state to disk prior to terminating).
The feature is currently not implemented; a request for draining in general is at [issue 41](https://github.com/containous/traefik/issues/41).

View File

@@ -2,7 +2,7 @@
This section explains how to create a multi-host docker cluster with
swarm mode using [docker-machine](https://docs.docker.com/machine) and
how to deploy Træfɪk on it.
how to deploy Træfik on it.
The cluster consists of:
@@ -22,7 +22,7 @@ The cluster consists of:
First, let's create all the required nodes. It's a shorter version of
the [swarm tutorial](https://docs.docker.com/engine/swarm/swarm-tutorial/).
```sh
```shell
docker-machine create -d virtualbox manager
docker-machine create -d virtualbox worker1
docker-machine create -d virtualbox worker2
@@ -34,7 +34,7 @@ Then, let's setup the cluster, in order :
2. get the token for other host to join
3. on both workers, join the cluster with the token
```sh
```shell
docker-machine ssh manager "docker swarm init \
--listen-addr $(docker-machine ip manager) \
--advertise-addr $(docker-machine ip manager)"
@@ -57,7 +57,7 @@ docker-machine ssh worker2 "docker swarm join \
Let's validate the cluster is up and running.
```sh
```shell
docker-machine ssh manager docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
2a770ov9vixeadep674265u1n worker1 Ready Active
@@ -67,7 +67,7 @@ esbhhy6vnqv90xomjaomdgy46 worker2 Ready Active
Finally, let's create a network for Træfik to use.
```sh
```shell
docker-machine ssh manager "docker network create --driver=overlay traefik-net"
```
@@ -79,7 +79,7 @@ on a manager node — we are going to use a
[constraint](https://docs.docker.com/engine/reference/commandline/service_create/#/specify-service-constraints-constraint) for
that.
```
```shell
docker-machine ssh manager "docker service create \
--name traefik \
--constraint=node.role==manager \
@@ -115,7 +115,7 @@ We can now deploy our app on the cluster,
here [whoami](https://github.com/emilevauge/whoami), a simple web
server in Go. We start 2 services, on the `traefik-net` network.
```sh
```shell
docker-machine ssh manager "docker service create \
--name whoami0 \
--label traefik.port=80 \
@@ -135,7 +135,7 @@ If using `docker stack deploy`, there is [a specific way that the labels must be
Check that everything is scheduled and started:
```sh
```shell
docker-machine ssh manager "docker service ls"
ID NAME REPLICAS IMAGE COMMAND
ab046gpaqtln whoami0 1/1 emilevauge/whoami
@@ -143,9 +143,9 @@ cgfg5ifzrpgm whoami1 1/1 emilevauge/whoami
dtpl249tfghc traefik 1/1 traefik --docker --docker.swarmmode --docker.domain=traefik --docker.watch --web
```
## Access to your apps through Træfɪk
## Access to your apps through Træfik
```sh
```shell
curl -H Host:whoami0.traefik http://$(docker-machine ip manager)
Hostname: 8147a7746e7a
IP: 127.0.0.1
@@ -186,7 +186,7 @@ X-Forwarded-Server: 8fbc39271b4c
Note that as Træfik is published, you can access it from any machine
and not only the manager.
```sh
```shell
curl -H Host:whoami0.traefik http://$(docker-machine ip worker1)
Hostname: 8147a7746e7a
IP: 127.0.0.1
@@ -226,7 +226,7 @@ X-Forwarded-Server: 8fbc39271b4c
## Scale both services
```sh
```shell
docker-machine ssh manager "docker service scale whoami0=5"
docker-machine ssh manager "docker service scale whoami1=5"
@@ -235,17 +235,17 @@ docker-machine ssh manager "docker service scale whoami1=5"
Check that we now have 5 replicas of each `whoami` service:
```sh
```shell
docker-machine ssh manager "docker service ls"
ID NAME REPLICAS IMAGE COMMAND
ab046gpaqtln whoami0 5/5 emilevauge/whoami
cgfg5ifzrpgm whoami1 5/5 emilevauge/whoami
dtpl249tfghc traefik 1/1 traefik --docker --docker.swarmmode --docker.domain=traefik --docker.watch --web
```
## Access to your whoami0 through Træfɪk multiple times.
## Access to your whoami0 through Træfik multiple times.
Repeat the following command multiple times and note that the Hostname changes each time as Traefik load balances each request against the 5 tasks.
```sh
```shell
curl -H Host:whoami0.traefik http://$(docker-machine ip manager)
Hostname: 8147a7746e7a
IP: 127.0.0.1
@@ -266,7 +266,7 @@ X-Forwarded-Server: 8fbc39271b4c
```
Do the same against whoami1.
```sh
```shell
curl -H Host:whoami1.traefik http://$(docker-machine ip manager)
Hostname: ba2c21488299
IP: 127.0.0.1
@@ -303,5 +303,3 @@ Now open your browser and go to http://whoami1.traefik/
You will now see that stickyness is maintained.
![](http://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -1,6 +1,6 @@
# Swarm cluster
This section explains how to create a multi-host [swarm](https://docs.docker.com/swarm) cluster using [docker-machine](https://docs.docker.com/machine/) and how to deploy Træfɪk on it.
This section explains how to create a multi-host [swarm](https://docs.docker.com/swarm) cluster using [docker-machine](https://docs.docker.com/machine/) and how to deploy Træfik on it.
The cluster consists of:
- 2 servers
@@ -21,13 +21,13 @@ We first follow [this guide](https://docs.docker.com/engine/userguide/networking
This machine is the service registry of our cluster.
```sh
```shell
docker-machine create -d virtualbox mh-keystore
```
Then we install the service registry [Consul](https://consul.io) on this machine:
```sh
```shell
eval "$(docker-machine env mh-keystore)"
docker run -d \
-p "8500:8500" \
@@ -39,7 +39,7 @@ docker run -d \
This machine is a swarm master and a swarm agent on it.
```sh
```shell
docker-machine create -d virtualbox \
--swarm --swarm-master \
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
@@ -52,7 +52,7 @@ docker-machine create -d virtualbox \
This machine have a swarm agent on it.
```sh
```shell
docker-machine create -d virtualbox \
--swarm \
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
@@ -65,16 +65,16 @@ docker-machine create -d virtualbox \
Create the overlay network on the swarm master:
```sh
```shell
eval $(docker-machine env --swarm mhs-demo0)
docker network create --driver overlay --subnet=10.0.9.0/24 my-net
```
## Deploy Træfɪk
## Deploy Træfik
Deploy Træfɪk:
Deploy Træfik:
```sh
```shell
docker $(docker-machine config mhs-demo0) run \
-d \
-p 80:80 -p 8080:8080 \
@@ -110,7 +110,7 @@ Let's explain this command:
We can now deploy our app on the cluster, here [whoami](https://github.com/emilevauge/whoami), a simple web server in GO, on the network `my-net`:
```sh
```shell
eval $(docker-machine env --swarm mhs-demo0)
docker run -d --name=whoami0 --net=my-net --env="constraint:node==mhs-demo0" emilevauge/whoami
docker run -d --name=whoami1 --net=my-net --env="constraint:node==mhs-demo1" emilevauge/whoami
@@ -118,7 +118,7 @@ docker run -d --name=whoami1 --net=my-net --env="constraint:node==mhs-demo1" emi
Check that everything is started:
```sh
```shell
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba2c21488299 emilevauge/whoami "/whoamI" 8 seconds ago Up 9 seconds 80/tcp mhs-demo1/whoami1
@@ -126,9 +126,9 @@ ba2c21488299 emilevauge/whoami "/whoamI" 8 seconds ago
8fbc39271b4c traefik "/traefik -l DEBUG -c" 36 seconds ago Up 37 seconds 192.168.99.101:80->80/tcp, 192.168.99.101:8080->8080/tcp mhs-demo0/serene_bhabha
```
## Access to your apps through Træfɪk
## Access to your apps through Træfik
```sh
```shell
curl -H Host:whoami0.traefik http://$(docker-machine ip mhs-demo0)
Hostname: 8147a7746e7a
IP: 127.0.0.1
@@ -167,4 +167,3 @@ X-Forwarded-Server: 8fbc39271b4c
```
![](http://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -1,9 +1,6 @@
traefik:
image: traefik
command: --web --rancher --rancher.domain=rancher.localhost --logLevel=DEBUG
labels:
io.rancher.container.agent.role: environment
io.rancher.container.create_agent: 'true'
command: --web --rancher --rancher.domain=rancher.localhost --rancher.endpoint=http://example.com --rancher.accesskey=XXXXXXX --rancher.secretkey=YYYYYY --logLevel=DEBUG
ports:
- "80:80"
- "443:443"

View File

@@ -3,7 +3,7 @@ kind: Ingress
metadata:
name: cheeses
annotations:
traefik.frontend.rule.type: pathprefixstrip
traefik.frontend.rule.type: PathPrefixStrip
spec:
rules:
- host: cheeses.local

View File

@@ -0,0 +1,37 @@
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- pods
- services
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system

View File

@@ -1,5 +1,11 @@
---
apiVersion: v1
kind: Deployment
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
---
kind: DaemonSet
apiVersion: extensions/v1beta1
metadata:
name: traefik-ingress-controller
@@ -7,16 +13,13 @@ metadata:
labels:
k8s-app: traefik-ingress-lb
spec:
replicas: 1
selector:
matchLabels:
k8s-app: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
hostNetwork: true
containers:
@@ -35,6 +38,8 @@ spec:
hostPort: 80
- name: admin
containerPort: 8081
securityContext:
privileged: true
args:
- -d
- --web

562
glide.lock generated
View File

@@ -1,20 +1,19 @@
hash: b689cb0faed68086641d9e3504ee29498e5bf06b088ad4fcd1e76543446d4d9a
updated: 2017-03-27T14:29:54.009570184+02:00
hash: 132846decb297148a6365019a486fc3cbadc96db8a20393bbf81512c0efd6197
updated: 2017-08-25T11:52:16.848940186+02:00
imports:
- name: bitbucket.org/ww/goautoneg
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
- name: cloud.google.com/go
version: c116c7972ec94f148459a304d07a67ecbc770d4b
version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c
subpackages:
- compute/metadata
- internal
- name: github.com/abbot/go-http-auth
version: cb4372376e1e00e9f6ab9ec142e029302c9e7140
version: d45c47bedec736d172957bd394786b76626fa8ac
- name: github.com/ArthurHlt/go-eureka-client
version: ba361cd0f9f571b4e871421423d2f02f5689c3d2
version: 9d0a49cbd39aa3634ae1977e9f519a262b10adaf
subpackages:
- eureka
- name: github.com/ArthurHlt/gominlog
version: 068c01ce147ad68fca25ef3fa29ae5395ae273ab
version: 72eebf980f467d3ab3a8b4ddf660f664911ce519
- name: github.com/aws/aws-sdk-go
version: 3f8f870ec9939e32b3372abf74d24e468bcd285d
subpackages:
@@ -44,46 +43,49 @@ imports:
- private/protocol/restxml
- private/protocol/xml/xmlutil
- private/waiter
- service/dynamodb
- service/dynamodb/dynamodbattribute
- service/dynamodb/dynamodbiface
- service/dynamodbattribute
- service/ec2
- service/ecs
- service/route53
- service/sts
- name: github.com/Azure/azure-sdk-for-go
version: 1620af6b32398bfc91827ceae54a8cc1f55df04d
version: 088007b3b08cc02b27f2eadfdcd870958460ce7e
subpackages:
- arm/dns
- name: github.com/Azure/go-autorest
version: 32cc2321122a649b7ba4e323527bcb145134fd47
version: a2fdd780c9a50455cecd249b00bdc3eb73a78e31
subpackages:
- autorest
- autorest/azure
- autorest/date
- autorest/to
- autorest/validation
- name: github.com/beorn7/perks
version: b965b613227fddccbfffe13eae360ed3fa822f8d
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
subpackages:
- quantile
- name: github.com/blang/semver
version: 3a37c301dda64cbe17f16f661b4c976803c0e2d2
version: 31b736133b98f26d5e078ec9eb591666edfd091f
- name: github.com/boltdb/bolt
version: 5cc10bbbc5c141029940133bb33c9e969512a698
version: e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
- name: github.com/BurntSushi/toml
version: 99064174e013895bbd9b025c31100bd1d9b590ca
version: b26d9c308763d68093482582cea63d69be07a0f0
- name: github.com/BurntSushi/ty
version: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74
subpackages:
- fun
- name: github.com/cenk/backoff
version: 8edc80b07f38c27352fb186d971c628a6c32552b
version: 5d150e7eec023ce7a124856b37c68e54b4050ac7
- name: github.com/codahale/hdrhistogram
version: 9208b142303c12d8899bae836fd524ac9338b4fd
- name: github.com/codegangsta/cli
version: bf4a526f48af7badd25d2cb02d587e1b01be3b50
- name: github.com/codegangsta/negroni
version: dc6b9d037e8dab60cbfc09c61d6932537829be8b
version: c0db5feaa33826cd5117930c8f4ee5c0f565eec6
- name: github.com/containous/flaeg
version: a731c034dda967333efce5f8d276aeff11f8ff87
version: b5d2dc5878df07c2d74413348186982e7b865871
- name: github.com/containous/mux
version: a819b77bba13f0c0cbe36e437bc2e948411b3996
- name: github.com/containous/staert
@@ -91,13 +93,17 @@ imports:
- name: github.com/coreos/etcd
version: c400d05d0aa73e21e431c16145e558d624098018
subpackages:
- Godeps/_workspace/src/github.com/coreos/go-systemd/journal
- Godeps/_workspace/src/github.com/coreos/pkg/capnslog
- Godeps/_workspace/src/github.com/ugorji/go/codec
- Godeps/_workspace/src/golang.org/x/net/context
- client
- pkg/fileutil
- pkg/pathutil
- pkg/types
- version
- name: github.com/coreos/go-oidc
version: 9e117111587506b9dc83b7b38263268bf48352ea
version: 5644a2f50e2d2d5ba0b474bc5bc55fea1925936d
subpackages:
- http
- jose
@@ -109,101 +115,32 @@ imports:
subpackages:
- daemon
- name: github.com/coreos/pkg
version: 2c77715c4df99b5420ffcae14ead08f52104065d
version: fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
subpackages:
- capnslog
- health
- httputil
- timeutil
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
subpackages:
- spew
- name: github.com/daviddengcn/go-colortext
version: 3b18c8575a432453d41fdafb340099fff5bba2f7
- name: github.com/decker502/dnspod-go
version: f6b1d56f1c048bd94d7e42ac36efb4d57b069b6f
version: 68650ee11e182e30773781d391c66a0c80ccf9f2
- name: github.com/dgrijalva/jwt-go
version: 9ed569b5d1ac936e6494082958d63a6aa4fff99a
version: d2709f9f1f31ebcda9651b03077758c1f3a0018c
- name: github.com/dnsimple/dnsimple-go
version: eeb343928d9a3de357a650c8c25d8f1318330d57
version: 5a5b427618a76f9eed5ede0f3e6306fbd9311d2e
subpackages:
- dnsimple
- name: github.com/docker/distribution
version: 325b0804fef3a66309d962357aac3c2ce3f4d329
subpackages:
- context
- digest
- reference
- registry/api/errcode
- registry/api/v2
- registry/client
- registry/client/auth
- registry/client/auth/challenge
- registry/client/transport
- registry/storage/cache
- registry/storage/cache/memory
- uuid
- name: github.com/docker/docker
version: 49bf474f9ed7ce7143a59d1964ff7b7fd9b52178
subpackages:
- api/types
- api/types/backend
- api/types/blkiodev
- api/types/container
- api/types/filters
- api/types/mount
- api/types/network
- api/types/registry
- api/types/strslice
- api/types/swarm
- api/types/versions
- builder
- builder/dockerignore
- cliconfig
- cliconfig/configfile
- daemon/graphdriver
- image
- image/v1
- layer
- namesgenerator
- oci
- opts
- pkg/archive
- pkg/chrootarchive
- pkg/fileutils
- pkg/gitutils
- pkg/homedir
- pkg/httputils
- pkg/idtools
- pkg/ioutils
- pkg/jsonlog
- pkg/jsonmessage
- pkg/longpath
- pkg/mount
- pkg/namesgenerator
- pkg/plugingetter
- pkg/plugins
- pkg/plugins/transport
- pkg/pools
- pkg/progress
- pkg/promise
- pkg/random
- pkg/reexec
- pkg/signal
- pkg/stdcopy
- pkg/streamformatter
- pkg/stringid
- pkg/symlink
- pkg/system
- pkg/tarsum
- pkg/term
- pkg/term/windows
- pkg/urlutil
- plugin/v2
- reference
- registry
- runconfig/opts
- name: github.com/docker/engine-api
version: 3d1601b9d2436a70b0dfc045a23f6503d19195df
subpackages:
@@ -231,9 +168,9 @@ imports:
- name: github.com/docker/go-units
version: 0dadbb0345b35ec7ef35e228dabb8de89a65bf52
- name: github.com/docker/leadership
version: bfc7753dd48af19513b29deec23c364bf0f274eb
version: 0a913e2d71a12fd14a028452435cb71ac8d82cb6
- name: github.com/docker/libkv
version: 35d3e2084c650109e7bcc7282655b1bc8ba924ff
version: 1d8431073ae03cdaedb198a89722f3aab6d418ef
subpackages:
- store
- store/boltdb
@@ -241,7 +178,7 @@ imports:
- store/etcd
- store/zookeeper
- name: github.com/donovanhide/eventsource
version: fd1de70867126402be23c306e1ce32828455d85b
version: 441a03aa37b3329bbb79f43de81914ea18724718
- name: github.com/eapache/channels
version: 47238d5aae8c0fefd518ef2bee46290909cf8263
- name: github.com/eapache/queue
@@ -255,18 +192,20 @@ imports:
- tokens
- zones
- name: github.com/elazarl/go-bindata-assetfs
version: 57eb5e1fc594ad4b0b1dbea7b286d299e0cb43c2
version: 30f82fa23fd844bd5bb1e5f216db87fd77b5eb43
- name: github.com/emicklei/go-restful
version: 892402ba11a2e2fd5e1295dd633481f27365f14d
subpackages:
- log
- swagger
- name: github.com/fatih/color
version: 9131ab34cf20d2f6d83fdc67168a5430d1c7dc23
- name: github.com/gambol99/go-marathon
version: 6b00a5b651b1beb2c6821863f7c60df490bd46c8
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
- name: github.com/ghodss/yaml
version: 04f313413ffd65ce25f2541bfd2b2ceec5c0908c
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
- name: github.com/go-ini/ini
version: 6f66b0e091edb3c7b380f7c4f0f884274d550b67
version: e7fea39b01aea8d5671f6858f0532f56e8bff3a5
- name: github.com/go-kit/kit
version: f66b0e13579bfc5a48b9e2a94b1209c107ea1f41
subpackages:
@@ -274,13 +213,13 @@ imports:
- metrics/internal/lv
- metrics/prometheus
- name: github.com/go-openapi/jsonpointer
version: 8d96a2dc61536b690bd36b2e9df0b3c0b62825b2
version: 46af16f9f7b149af66e5d1bd010e3574dc06de98
- name: github.com/go-openapi/jsonreference
version: 36d33bfe519efae5632669801b180bf1a245da3b
version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272
- name: github.com/go-openapi/spec
version: 34b5ffff717ab4535aef76e3dd90818bddde571b
version: 6aced65f8501fe1217321abf0749d354824ba2ff
- name: github.com/go-openapi/swag
version: 96d7b9ebd181a1735a1c9ac87914f2b32fbf56c9
version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72
- name: github.com/gogo/protobuf
version: 909568be09de550ed094403c2bf8a261b5bb730a
subpackages:
@@ -289,38 +228,39 @@ imports:
- name: github.com/golang/glog
version: fca8c8854093a154ff1eb580aae10276ad6b1b5f
- name: github.com/golang/protobuf
version: 5677a0e3d5e89854c9974e1256839ee23f8233ca
version: 2bba0603135d7d7f5cb73b2125beeda19c09f4ef
subpackages:
- proto
- name: github.com/google/go-github
version: c8ebe3a4d7f0791a6315b7410353d4084c58805d
version: 6896997c7c9fe603fb9d2e8e92303bb18481e60a
subpackages:
- github
- name: github.com/google/go-querystring
version: 9235644dd9e52eeae6fa48efd539fdc351a0af53
version: 53e6ce116135b80d037921a7fdd5138cf32d7a8a
subpackages:
- query
- name: github.com/google/gofuzz
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5
- name: github.com/googleapis/gax-go
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
- name: github.com/gorilla/context
version: 1ea25387ff6f684839d82767c1733ff4d4d15d0a
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
- name: github.com/gorilla/websocket
version: 4873052237e4eeda85cf50c071ef33836fe8e139
version: a69d9f6de432e2c6b296a947d8a5ee88f68522cf
- name: github.com/hashicorp/consul
version: fce7d75609a04eeb9d4bf41c8dc592aac18fc97d
version: 3f92cc70e8163df866873c16c6d89889b5c95fc4
subpackages:
- api
- name: github.com/hashicorp/go-cleanhttp
version: 875fb671b3ddc66f8e2f0acc33829c8cb989a38d
version: 3573b8b52aa7b37b9358d966a898feb387f62437
- name: github.com/hashicorp/go-version
version: e96d3840402619007766590ecea8dd7af1292276
version: 03c5bf6be031b6dd45afec16b1cf94fc8938bc77
- name: github.com/hashicorp/serf
version: 6c4672d66fc6312ddde18399262943e21175d831
version: 19f2c401e122352c047a84d6584dd51e2fb8fcc4
subpackages:
- coordinate
- serf
- name: github.com/JamesClonk/vultr
version: 9ec0427d51411407c0402b093a1771cb75af9679
version: 0f156dd232bc4ebf8a32ba83fec57c0e4c9db69f
subpackages:
- lib
- name: github.com/jmespath/go-jmespath
@@ -329,20 +269,24 @@ imports:
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
- name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/mailgun/manners
version: a585afd9d65c0e05f6c003f921e71ebc05074f4f
- name: github.com/mailgun/timetools
version: fd192d755b00c968d312d23f521eb0cdc6f66bd0
- name: github.com/mailru/easyjson
version: 9d6630dc8c577b56cb9687a9cf9e8578aca7298a
version: d5b7844b561a7bc640052f1b935f7b800330d7e0
subpackages:
- buffer
- jlexer
- jwriter
- name: github.com/mattn/go-colorable
version: 5411d3eea5978e6cdc258b30de592b60df6aba96
repo: https://github.com/mattn/go-colorable
- name: github.com/mattn/go-isatty
version: 57fdcb988a5c543893cc61bce354a6e24ab70022
repo: https://github.com/mattn/go-isatty
- name: github.com/mattn/go-shellwords
version: 525bedee691b5a8df547cb5cf9f86b7fb1883e24
version: 02e3cf038dcea8290e44424da473dd12be796a8a
- name: github.com/matttproud/golang_protobuf_extensions
version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
subpackages:
- pbutil
- name: github.com/mesos/mesos-go
@@ -368,58 +312,60 @@ imports:
- records/state
- util
- name: github.com/Microsoft/go-winio
version: ce2922f643c8fd76b46cadc7f404a06282678b34
version: fff283ad5116362ca252298cfc9b95828956d85d
- name: github.com/miekg/dns
version: 8060d9f51305bbe024b99679454e62f552cd0b0b
- name: github.com/mitchellh/mapstructure
version: f3009df150dadf309fdee4a54ed65c124afad715
version: 53818660ed4955e899c0bcafa97299a388bd7c8e
- name: github.com/mvdan/xurls
version: fa08908f19eca8c491d68c6bd8b4b44faea6daf8
version: db96455566f05ffe42bd6ac671f05eeb1152b45d
- name: github.com/NYTimes/gziphandler
version: 6710af535839f57c687b62c4c23d649f9545d885
version: 824b33f2a7457025697878c865c323f801118043
repo: https://github.com/containous/gziphandler.git
vcs: git
- name: github.com/ogier/pflag
version: 45c278ab3607870051a2ea9040bb85fcb8557481
- name: github.com/opencontainers/runc
version: 1a81e9ab1f138c091fe5c86d0883f87716088527
version: 50401b5b4c2e01e4f1372b73a021742deeaf4e2d
subpackages:
- libcontainer/configs
- libcontainer/devices
- libcontainer/system
- libcontainer/user
- name: github.com/ovh/go-ovh
version: a8a4c0bc40e56322142649bda7b2b4bb15145b6e
version: d2207178e10e4527e8f222fd8707982df8c3af17
subpackages:
- ovh
- name: github.com/pborman/uuid
version: 5007efa264d92316c43112bc573e754bc889b7b1
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/pkg/errors
version: bfd5150e4e41705ded2129ec33379de1cb90b513
version: ff09b135c25aae272398c51a07235b90a75aa4f0
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/prometheus/client_golang
version: c5b7fccd204277076155f10851dad72b76a49317
version: 08fd2e12372a66e68e30523c7642e0cbc3e4fbde
subpackages:
- prometheus
- prometheus/promhttp
- name: github.com/prometheus/client_model
version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6
version: 6f3806018612930941127f2a7c6c453ba2c527d2
subpackages:
- go
- name: github.com/prometheus/common
version: ffe929a3f4c4faeaa10f2b9535c2b1be3ad15650
version: 49fee292b27bfff7f354ee0f64e1bc4850462edf
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
version: 454a56f35412459b5e684fd5ec0f9211b94f002a
version: a1dba9ce8baed984a2495b658c82687f8157b98f
subpackages:
- xfs
- name: github.com/PuerkitoBio/purell
version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4
version: 8a290539e2e8629dbc4e6bad948158f790ec31f4
- name: github.com/PuerkitoBio/urlesc
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
- name: github.com/pyr/egoscale
version: ab4b0d7ff424c462da486aef27f354cdeb29a319
version: 987e683a7552f34ee586217d1cc8507d52e80ab9
subpackages:
- src/egoscale
- name: github.com/rancher/go-rancher
@@ -427,26 +373,27 @@ imports:
subpackages:
- client
- name: github.com/ryanuber/go-glob
version: 572520ed46dbddaed19ea3d9541bdd0494163693
version: 256dc444b735e061061cf46c809487313d5b0065
- name: github.com/samuel/go-zookeeper
version: e64db453f3512cade908163702045e0f31137843
version: 1d7be4effb13d2d908342d349d71a284a7542693
subpackages:
- zk
- name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/Sirupsen/logrus
version: a283a10442df8dc09befd873fab202bf8a253d6a
version: 10f801ebc38b33738c9d17d50860f484a0988ff5
- name: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842
version: 5ccb023bc27df288a957c5e994cd44fd19619465
- name: github.com/streamrail/concurrent-map
version: 65a174a3a4188c0b7099acbc6cfa0c53628d3287
version: 8bf1e9bacbf65b10c81d0f4314cf2b1ebef728b5
- name: github.com/stretchr/objx
version: cbeaeb16a013161a98496fad62933b1d21786672
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
version: 4d4bfba8f1d1027c4fdbe371823030df51419987
subpackages:
- assert
- mock
- require
- name: github.com/thoas/stats
version: 152b5d051953fdb6e45f14b6826962aadc032324
- name: github.com/timewasted/linode
@@ -460,11 +407,11 @@ imports:
subpackages:
- codec
- name: github.com/unrolled/render
version: 198ad4d8b8a4612176b804ca10555b222a086b40
version: 50716a0a853771bb36bfce61a45cdefdb98c2e6e
- name: github.com/vdemeester/docker-events
version: be74d4929ec1ad118df54349fda4b0cba60f849b
- name: github.com/vulcand/oxy
version: f88530866c561d24a6b5aac49f76d6351b788b9f
version: 6c94d2888dba2b1a15a89b8a2ca515fc85e07477
repo: https://github.com/containous/oxy.git
vcs: git
subpackages:
@@ -487,7 +434,7 @@ imports:
- plugin/rewrite
- router
- name: github.com/xenolf/lego
version: 0e2937900b224325f4476745a9b53aef246b7410
version: 5dfe609afb1ebe9da97c9846d97a55415e5a5ccd
subpackages:
- acme
- providers/dns
@@ -525,28 +472,34 @@ imports:
- http2
- http2/hpack
- idna
- internal/timeseries
- lex/httplex
- proxy
- publicsuffix
- trace
- name: golang.org/x/oauth2
version: 3046bc76d6dfd7d3707f6640f85e42d9c4050f50
version: 7fdf09982454086d5570c7db3e11f360194830ca
subpackages:
- google
- internal
- jws
- jwt
- name: golang.org/x/sys
version: eb2c74142fd19a79b3f237334c7384d5167b1b46
version: 8d1157a435470616f975ff9bb013bea8d0962067
subpackages:
- unix
- windows
- name: golang.org/x/text
version: a49bea13b776691cb1b49873e5d8df96ec74831a
repo: https://github.com/golang/text.git
vcs: git
version: 2910a502d2bf9e43193af9d68ca516529614eed3
subpackages:
- .
- cases
- internal/tag
- language
- runes
- secure/bidirule
- secure/precis
- transform
- unicode/bidi
- unicode/norm
- width
- name: google.golang.org/api
@@ -557,7 +510,7 @@ imports:
- googleapi
- googleapi/internal/uritemplates
- name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
version: 4f7eeb5305a4ba1966344836ba4af9996b7b4e05
subpackages:
- internal
- internal/app_identity
@@ -568,23 +521,33 @@ imports:
- internal/remote_api
- internal/urlfetch
- urlfetch
- name: google.golang.org/cloud
version: f20d6dcccb44ed49de45ae3703312cb46e627db1
- name: google.golang.org/grpc
version: cdee119ee21e61eef7093a41ba148fa83585e143
subpackages:
- compute/metadata
- codes
- credentials
- grpclog
- internal
- keepalive
- metadata
- naming
- peer
- stats
- tap
- transport
- name: gopkg.in/fsnotify.v1
version: a8a77c9133d2d6fd8334f3260d06f60e8d80a5fb
version: 629574ca2a5df945712d3079857300b5e4da0236
- name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/ini.v1
version: 6f66b0e091edb3c7b380f7c4f0f884274d550b67
version: e7fea39b01aea8d5671f6858f0532f56e8bff3a5
- name: gopkg.in/mgo.v2
version: 29cc868a5ca65f401ff318143f9408d02f4799cc
version: 3f83fa5005286a7fe593b055f0d7771a7dce4655
subpackages:
- bson
- internal/json
- name: gopkg.in/ns1/ns1-go.v2
version: d8d10b7f448291ddbdce48d4594fb1b667014c8b
version: 2abc76c60bf88ba33b15d1d87a13f624d8dff956
subpackages:
- rest
- rest/model/account
@@ -593,175 +556,120 @@ imports:
- rest/model/filter
- rest/model/monitor
- name: gopkg.in/square/go-jose.v1
version: e3f973b66b91445ec816dd7411ad1b6495a5a2fc
version: aa2e30fdd1fe9dd3394119af66451ae790d50e0d
subpackages:
- cipher
- json
- name: gopkg.in/yaml.v2
version: bef53efd0c76e49e6de55ead051f886bea7e9420
version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
- name: k8s.io/client-go
version: 1195e3a8ee1a529d53eed7c624527a68555ddf1f
version: e121606b0d09b2e1c467183ee46217fa85a6b672
subpackages:
- 1.5/discovery
- 1.5/kubernetes
- 1.5/kubernetes/typed/apps/v1alpha1
- 1.5/kubernetes/typed/authentication/v1beta1
- 1.5/kubernetes/typed/authorization/v1beta1
- 1.5/kubernetes/typed/autoscaling/v1
- 1.5/kubernetes/typed/batch/v1
- 1.5/kubernetes/typed/certificates/v1alpha1
- 1.5/kubernetes/typed/core/v1
- 1.5/kubernetes/typed/extensions/v1beta1
- 1.5/kubernetes/typed/policy/v1alpha1
- 1.5/kubernetes/typed/rbac/v1alpha1
- 1.5/kubernetes/typed/storage/v1beta1
- 1.5/pkg/api
- 1.5/pkg/api/errors
- 1.5/pkg/api/install
- 1.5/pkg/api/meta
- 1.5/pkg/api/meta/metatypes
- 1.5/pkg/api/resource
- 1.5/pkg/api/unversioned
- 1.5/pkg/api/v1
- 1.5/pkg/api/validation/path
- 1.5/pkg/apimachinery
- 1.5/pkg/apimachinery/announced
- 1.5/pkg/apimachinery/registered
- 1.5/pkg/apis/apps
- 1.5/pkg/apis/apps/install
- 1.5/pkg/apis/apps/v1alpha1
- 1.5/pkg/apis/authentication
- 1.5/pkg/apis/authentication/install
- 1.5/pkg/apis/authentication/v1beta1
- 1.5/pkg/apis/authorization
- 1.5/pkg/apis/authorization/install
- 1.5/pkg/apis/authorization/v1beta1
- 1.5/pkg/apis/autoscaling
- 1.5/pkg/apis/autoscaling/install
- 1.5/pkg/apis/autoscaling/v1
- 1.5/pkg/apis/batch
- 1.5/pkg/apis/batch/install
- 1.5/pkg/apis/batch/v1
- 1.5/pkg/apis/batch/v2alpha1
- 1.5/pkg/apis/certificates
- 1.5/pkg/apis/certificates/install
- 1.5/pkg/apis/certificates/v1alpha1
- 1.5/pkg/apis/extensions
- 1.5/pkg/apis/extensions/install
- 1.5/pkg/apis/extensions/v1beta1
- 1.5/pkg/apis/policy
- 1.5/pkg/apis/policy/install
- 1.5/pkg/apis/policy/v1alpha1
- 1.5/pkg/apis/rbac
- 1.5/pkg/apis/rbac/install
- 1.5/pkg/apis/rbac/v1alpha1
- 1.5/pkg/apis/storage
- 1.5/pkg/apis/storage/install
- 1.5/pkg/apis/storage/v1beta1
- 1.5/pkg/auth/user
- 1.5/pkg/conversion
- 1.5/pkg/conversion/queryparams
- 1.5/pkg/fields
- 1.5/pkg/genericapiserver/openapi/common
- 1.5/pkg/labels
- 1.5/pkg/runtime
- 1.5/pkg/runtime/serializer
- 1.5/pkg/runtime/serializer/json
- 1.5/pkg/runtime/serializer/protobuf
- 1.5/pkg/runtime/serializer/recognizer
- 1.5/pkg/runtime/serializer/streaming
- 1.5/pkg/runtime/serializer/versioning
- 1.5/pkg/selection
- 1.5/pkg/third_party/forked/golang/reflect
- 1.5/pkg/types
- 1.5/pkg/util
- 1.5/pkg/util/cert
- 1.5/pkg/util/clock
- 1.5/pkg/util/errors
- 1.5/pkg/util/flowcontrol
- 1.5/pkg/util/framer
- 1.5/pkg/util/integer
- 1.5/pkg/util/intstr
- 1.5/pkg/util/json
- 1.5/pkg/util/labels
- 1.5/pkg/util/net
- 1.5/pkg/util/parsers
- 1.5/pkg/util/rand
- 1.5/pkg/util/runtime
- 1.5/pkg/util/sets
- 1.5/pkg/util/uuid
- 1.5/pkg/util/validation
- 1.5/pkg/util/validation/field
- 1.5/pkg/util/wait
- 1.5/pkg/util/yaml
- 1.5/pkg/version
- 1.5/pkg/watch
- 1.5/pkg/watch/versioned
- 1.5/plugin/pkg/client/auth
- 1.5/plugin/pkg/client/auth/gcp
- 1.5/plugin/pkg/client/auth/oidc
- 1.5/rest
- 1.5/tools/cache
- 1.5/tools/clientcmd/api
- 1.5/tools/metrics
- 1.5/transport
testImports:
- name: github.com/Azure/go-ansiterm
version: fa152c58bc15761d0200cb75fe958b89a9d4888e
subpackages:
- winterm
- name: github.com/cloudfoundry-incubator/candiedyaml
version: 99c3df83b51532e3615f851d8c2dbb638f5313bf
- name: github.com/docker/libcompose
version: d1876c1d68527a49c0aac22a0b161acc7296b740
subpackages:
- config
- docker
- docker/builder
- docker/client
- docker/network
- labels
- logger
- lookup
- project
- project/events
- project/options
- utils
- version
- yaml
- name: github.com/flynn/go-shlex
version: 3f9db97f856818214da2e1057f8ad84803971cff
- name: github.com/go-check/check
version: 11d3bc7aa68e238947792f30573146a3231fc0f1
- name: github.com/gorilla/mux
version: e444e69cbd2e2e3e0749a2f3c717cec491552bbf
- name: github.com/libkermit/compose
version: cadc5a3b83a15790174bd7fbc75ea2529785e772
subpackages:
- check
- name: github.com/libkermit/docker
version: 55e3595409924fcfbb850811e5a7cdbe8960a0b7
- name: github.com/libkermit/docker-check
version: cbe0ef03b3d23070eac4d00ba8828f2cc7f7e5a3
- name: github.com/opencontainers/runtime-spec
version: 06479209bdc0d4135911688c18157bd39bd99c22
subpackages:
- specs-go
- name: github.com/vbatts/tar-split
version: 6810cedb21b2c3d0b9bb8f9af12ff2dc7a2f14df
subpackages:
- archive/tar
- tar/asm
- tar/storage
- name: github.com/vdemeester/shakers
version: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
- name: github.com/xeipuuv/gojsonpointer
version: e0fe6f68307607d540ed8eac07a342c33fa1b54a
- name: github.com/xeipuuv/gojsonreference
version: e02fc20de94c78484cd5ffb007f8af96be030a45
- name: github.com/xeipuuv/gojsonschema
version: 00f9fafb54d2244d291b86ab63d12c38bd5c3886
- name: golang.org/x/time
version: a4bde12657593d5e90d0533a3e4fd95e635124cb
subpackages:
- rate
- discovery
- kubernetes
- kubernetes/typed/apps/v1beta1
- kubernetes/typed/authentication/v1beta1
- kubernetes/typed/authorization/v1beta1
- kubernetes/typed/autoscaling/v1
- kubernetes/typed/batch/v1
- kubernetes/typed/batch/v2alpha1
- kubernetes/typed/certificates/v1alpha1
- kubernetes/typed/core/v1
- kubernetes/typed/extensions/v1beta1
- kubernetes/typed/policy/v1beta1
- kubernetes/typed/rbac/v1alpha1
- kubernetes/typed/storage/v1beta1
- pkg/api
- pkg/api/errors
- pkg/api/install
- pkg/api/meta
- pkg/api/meta/metatypes
- pkg/api/resource
- pkg/api/unversioned
- pkg/api/v1
- pkg/api/validation/path
- pkg/apimachinery
- pkg/apimachinery/announced
- pkg/apimachinery/registered
- pkg/apis/apps
- pkg/apis/apps/install
- pkg/apis/apps/v1beta1
- pkg/apis/authentication
- pkg/apis/authentication/install
- pkg/apis/authentication/v1beta1
- pkg/apis/authorization
- pkg/apis/authorization/install
- pkg/apis/authorization/v1beta1
- pkg/apis/autoscaling
- pkg/apis/autoscaling/install
- pkg/apis/autoscaling/v1
- pkg/apis/batch
- pkg/apis/batch/install
- pkg/apis/batch/v1
- pkg/apis/batch/v2alpha1
- pkg/apis/certificates
- pkg/apis/certificates/install
- pkg/apis/certificates/v1alpha1
- pkg/apis/extensions
- pkg/apis/extensions/install
- pkg/apis/extensions/v1beta1
- pkg/apis/policy
- pkg/apis/policy/install
- pkg/apis/policy/v1beta1
- pkg/apis/rbac
- pkg/apis/rbac/install
- pkg/apis/rbac/v1alpha1
- pkg/apis/storage
- pkg/apis/storage/install
- pkg/apis/storage/v1beta1
- pkg/auth/user
- pkg/conversion
- pkg/conversion/queryparams
- pkg/fields
- pkg/genericapiserver/openapi/common
- pkg/labels
- pkg/runtime
- pkg/runtime/serializer
- pkg/runtime/serializer/json
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer
- pkg/runtime/serializer/streaming
- pkg/runtime/serializer/versioning
- pkg/selection
- pkg/third_party/forked/golang/reflect
- pkg/third_party/forked/golang/template
- pkg/types
- pkg/util
- pkg/util/cert
- pkg/util/clock
- pkg/util/diff
- pkg/util/errors
- pkg/util/flowcontrol
- pkg/util/framer
- pkg/util/integer
- pkg/util/intstr
- pkg/util/json
- pkg/util/jsonpath
- pkg/util/labels
- pkg/util/net
- pkg/util/parsers
- pkg/util/rand
- pkg/util/runtime
- pkg/util/sets
- pkg/util/uuid
- pkg/util/validation
- pkg/util/validation/field
- pkg/util/wait
- pkg/util/yaml
- pkg/version
- pkg/watch
- pkg/watch/versioned
- plugin/pkg/client/auth
- plugin/pkg/client/auth/gcp
- plugin/pkg/client/auth/oidc
- rest
- tools/cache
- tools/clientcmd/api
- tools/metrics
- transport
testImports: []

View File

@@ -7,9 +7,8 @@ import:
- package: github.com/Sirupsen/logrus
- package: github.com/cenk/backoff
- package: github.com/containous/flaeg
version: a731c034dda967333efce5f8d276aeff11f8ff87
- package: github.com/vulcand/oxy
version: f88530866c561d24a6b5aac49f76d6351b788b9f
version: 6c94d2888dba2b1a15a89b8a2ca515fc85e07477
repo: https://github.com/containous/oxy.git
vcs: git
subpackages:
@@ -47,11 +46,12 @@ import:
- package: github.com/hashicorp/consul
subpackages:
- api
- package: github.com/mailgun/manners
- package: github.com/streamrail/concurrent-map
- package: github.com/stretchr/testify
subpackages:
- assert
- mock
- require
- package: github.com/thoas/stats
version: 152b5d051953fdb6e45f14b6826962aadc032324
- package: github.com/unrolled/render
@@ -62,7 +62,7 @@ import:
subpackages:
- plugin/rewrite
- package: github.com/xenolf/lego
version: 0e2937900b224325f4476745a9b53aef246b7410
version: 5dfe609afb1ebe9da97c9846d97a55415e5a5ccd
subpackages:
- acme
- package: gopkg.in/fsnotify.v1
@@ -87,13 +87,16 @@ import:
vcs: git
- package: github.com/abbot/go-http-auth
- package: github.com/NYTimes/gziphandler
repo: https://github.com/containous/gziphandler.git
version: ^v1002.0.0
vcs: git
- package: github.com/docker/leadership
- package: github.com/satori/go.uuid
version: ^1.1.0
- package: k8s.io/client-go
version: ^v1.5.0
version: v2.0.0
- package: github.com/gambol99/go-marathon
version: ^0.5.1
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
- package: github.com/ArthurHlt/go-eureka-client
subpackages:
- eureka
@@ -110,6 +113,8 @@ import:
- metrics
- package: github.com/eapache/channels
version: v1.1.0
- package: golang.org/x/sys
version: 8d1157a435470616f975ff9bb013bea8d0962067
- package: golang.org/x/net
version: 242b6b35177ec3909636b6cf6a47e8c2c6324b5d
subpackages:
@@ -127,10 +132,13 @@ import:
- aws/endpoints
- aws/request
- aws/session
- service/dynamodb
- service/dynamodb/dynamodbiface
- service/dynamodbattribute
- service/ec2
- service/ecs
- package: cloud.google.com/go
version: v0.6.0
version: v0.7.0
subpackages:
- compute/metadata
- package: github.com/gogo/protobuf
@@ -139,3 +147,9 @@ import:
- proto
- package: github.com/rancher/go-rancher
version: 5b8f6cc26b355ba03d7611fce3844155b7baf05b
- package: golang.org/x/oauth2/google
version: 7fdf09982454086d5570c7db3e11f360194830ca
- package: github.com/googleapis/gax-go
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
- package: google.golang.org/grpc
version: v1.2.0

View File

@@ -2,6 +2,7 @@ package healthcheck
import (
"context"
"fmt"
"net/http"
"net/url"
"sync"
@@ -15,7 +16,7 @@ import (
var singleton *HealthCheck
var once sync.Once
// GetHealthCheck Get HealtchCheck Singleton
// GetHealthCheck returns the health check which is guaranteed to be a singleton.
func GetHealthCheck() *HealthCheck {
once.Do(func() {
singleton = newHealthCheck()
@@ -23,15 +24,23 @@ func GetHealthCheck() *HealthCheck {
return singleton
}
// BackendHealthCheck HealthCheck configuration for a backend
type BackendHealthCheck struct {
Path string
Interval time.Duration
DisabledURLs []*url.URL
lb loadBalancer
// Options are the public health check options.
type Options struct {
Path string
Interval time.Duration
LB LoadBalancer
}
var launch = false
func (opt Options) String() string {
return fmt.Sprintf("[Path: %s Interval: %s]", opt.Path, opt.Interval)
}
// BackendHealthCheck HealthCheck configuration for a backend
type BackendHealthCheck struct {
Options
disabledURLs []*url.URL
requestTimeout time.Duration
}
//HealthCheck struct
type HealthCheck struct {
@@ -39,19 +48,25 @@ type HealthCheck struct {
cancel context.CancelFunc
}
type loadBalancer interface {
// LoadBalancer includes functionality for load-balancing management.
type LoadBalancer interface {
RemoveServer(u *url.URL) error
UpsertServer(u *url.URL, options ...roundrobin.ServerOption) error
Servers() []*url.URL
}
func newHealthCheck() *HealthCheck {
return &HealthCheck{make(map[string]*BackendHealthCheck), nil}
return &HealthCheck{
Backends: make(map[string]*BackendHealthCheck),
}
}
// NewBackendHealthCheck Instantiate a new BackendHealthCheck
func NewBackendHealthCheck(URL string, interval time.Duration, lb loadBalancer) *BackendHealthCheck {
return &BackendHealthCheck{URL, interval, nil, lb}
func NewBackendHealthCheck(options Options) *BackendHealthCheck {
return &BackendHealthCheck{
Options: options,
requestTimeout: 5 * time.Second,
}
}
//SetBackendsConfiguration set backends configuration
@@ -62,56 +77,63 @@ func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backe
}
ctx, cancel := context.WithCancel(parentCtx)
hc.cancel = cancel
hc.execute(ctx)
}
func (hc *HealthCheck) execute(ctx context.Context) {
for backendID, backend := range hc.Backends {
currentBackend := backend
currentBackendID := backendID
currentBackend := backend
safe.Go(func() {
for {
ticker := time.NewTicker(currentBackend.Interval)
select {
case <-ctx.Done():
log.Debugf("Stopping all current Healthcheck goroutines")
return
case <-ticker.C:
log.Debugf("Refreshing Healthcheck for currentBackend %s ", currentBackendID)
enabledURLs := currentBackend.lb.Servers()
var newDisabledURLs []*url.URL
for _, url := range currentBackend.DisabledURLs {
if checkHealth(url, currentBackend.Path) {
log.Debugf("HealthCheck is up [%s]: Upsert in server list", url.String())
currentBackend.lb.UpsertServer(url, roundrobin.Weight(1))
} else {
newDisabledURLs = append(newDisabledURLs, url)
}
}
currentBackend.DisabledURLs = newDisabledURLs
for _, url := range enabledURLs {
if !checkHealth(url, currentBackend.Path) {
log.Debugf("HealthCheck has failed [%s]: Remove from server list", url.String())
currentBackend.lb.RemoveServer(url)
currentBackend.DisabledURLs = append(currentBackend.DisabledURLs, url)
}
}
}
}
hc.execute(ctx, currentBackendID, currentBackend)
})
}
}
func checkHealth(serverURL *url.URL, path string) bool {
timeout := time.Duration(5 * time.Second)
client := http.Client{
Timeout: timeout,
func (hc *HealthCheck) execute(ctx context.Context, backendID string, backend *BackendHealthCheck) {
log.Debugf("Initial healthcheck for currentBackend %s ", backendID)
checkBackend(backend)
ticker := time.NewTicker(backend.Interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
log.Debugf("Stopping all current Healthcheck goroutines")
return
case <-ticker.C:
log.Debugf("Refreshing healthcheck for currentBackend %s ", backendID)
checkBackend(backend)
}
}
resp, err := client.Get(serverURL.String() + path)
if err != nil || resp.StatusCode != 200 {
return false
}
return true
}
func checkBackend(currentBackend *BackendHealthCheck) {
enabledURLs := currentBackend.LB.Servers()
var newDisabledURLs []*url.URL
for _, url := range currentBackend.disabledURLs {
if checkHealth(url, currentBackend) {
log.Debugf("HealthCheck is up [%s]: Upsert in server list", url.String())
currentBackend.LB.UpsertServer(url, roundrobin.Weight(1))
} else {
log.Warnf("HealthCheck is still failing [%s]", url.String())
newDisabledURLs = append(newDisabledURLs, url)
}
}
currentBackend.disabledURLs = newDisabledURLs
for _, url := range enabledURLs {
if !checkHealth(url, currentBackend) {
log.Warnf("HealthCheck has failed [%s]: Remove from server list", url.String())
currentBackend.LB.RemoveServer(url)
currentBackend.disabledURLs = append(currentBackend.disabledURLs, url)
}
}
}
func checkHealth(serverURL *url.URL, backend *BackendHealthCheck) bool {
client := http.Client{
Timeout: backend.requestTimeout,
}
resp, err := client.Get(serverURL.String() + backend.Path)
if err == nil {
defer resp.Body.Close()
}
return err == nil && resp.StatusCode == 200
}

View File

@@ -0,0 +1,202 @@
package healthcheck
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"sync"
"testing"
"time"
"github.com/vulcand/oxy/roundrobin"
)
const healthCheckInterval = 100 * time.Millisecond
type testLoadBalancer struct {
// RWMutex needed due to parallel test execution: Both the system-under-test
// and the test assertions reference the counters.
*sync.RWMutex
numRemovedServers int
numUpsertedServers int
servers []*url.URL
}
func (lb *testLoadBalancer) RemoveServer(u *url.URL) error {
lb.Lock()
defer lb.Unlock()
lb.numRemovedServers++
lb.removeServer(u)
return nil
}
func (lb *testLoadBalancer) UpsertServer(u *url.URL, options ...roundrobin.ServerOption) error {
lb.Lock()
defer lb.Unlock()
lb.numUpsertedServers++
lb.servers = append(lb.servers, u)
return nil
}
func (lb *testLoadBalancer) Servers() []*url.URL {
return lb.servers
}
func (lb *testLoadBalancer) removeServer(u *url.URL) {
var i int
var serverURL *url.URL
for i, serverURL = range lb.servers {
if *serverURL == *u {
break
}
}
lb.servers = append(lb.servers[:i], lb.servers[i+1:]...)
}
type testHandler struct {
done func()
healthSequence []bool
}
func newTestServer(done func(), healthSequence []bool) *httptest.Server {
handler := &testHandler{
done: done,
healthSequence: healthSequence,
}
return httptest.NewServer(handler)
}
// ServeHTTP returns 200 or 503 HTTP response codes depending on whether the
// current request is marked as healthy or not.
// It calls the given 'done' function once all request health indicators have
// been depleted.
func (th *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(th.healthSequence) == 0 {
panic("received unexpected request")
}
healthy := th.healthSequence[0]
if healthy {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
th.healthSequence = th.healthSequence[1:]
if len(th.healthSequence) == 0 {
th.done()
}
}
func TestSetBackendsConfiguration(t *testing.T) {
tests := []struct {
desc string
startHealthy bool
healthSequence []bool
wantNumRemovedServers int
wantNumUpsertedServers int
}{
{
desc: "healthy server staying healthy",
startHealthy: true,
healthSequence: []bool{true},
wantNumRemovedServers: 0,
wantNumUpsertedServers: 0,
},
{
desc: "healthy server becoming sick",
startHealthy: true,
healthSequence: []bool{false},
wantNumRemovedServers: 1,
wantNumUpsertedServers: 0,
},
{
desc: "sick server becoming healthy",
startHealthy: false,
healthSequence: []bool{true},
wantNumRemovedServers: 0,
wantNumUpsertedServers: 1,
},
{
desc: "sick server staying sick",
startHealthy: false,
healthSequence: []bool{false},
wantNumRemovedServers: 0,
wantNumUpsertedServers: 0,
},
{
desc: "healthy server toggling to sick and back to healthy",
startHealthy: true,
healthSequence: []bool{false, true},
wantNumRemovedServers: 1,
wantNumUpsertedServers: 1,
},
}
for _, test := range tests {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
// The context is passed to the health check and canonically cancelled by
// the test server once all expected requests have been received.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ts := newTestServer(cancel, test.healthSequence)
defer ts.Close()
lb := &testLoadBalancer{RWMutex: &sync.RWMutex{}}
backend := NewBackendHealthCheck(Options{
Path: "/path",
Interval: healthCheckInterval,
LB: lb,
})
serverURL := MustParseURL(ts.URL)
if test.startHealthy {
lb.servers = append(lb.servers, serverURL)
} else {
backend.disabledURLs = append(backend.disabledURLs, serverURL)
}
healthCheck := HealthCheck{
Backends: make(map[string]*BackendHealthCheck),
}
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
healthCheck.execute(ctx, "id", backend)
wg.Done()
}()
// Make test timeout dependent on number of expected requests, health
// check interval, and a safety margin.
timeout := time.Duration(len(test.healthSequence)*int(healthCheckInterval) + 500)
select {
case <-time.After(timeout):
t.Fatal("test did not complete in time")
case <-ctx.Done():
wg.Wait()
}
lb.Lock()
defer lb.Unlock()
if lb.numRemovedServers != test.wantNumRemovedServers {
t.Errorf("got %d removed servers, wanted %d", lb.numRemovedServers, test.wantNumRemovedServers)
}
if lb.numUpsertedServers != test.wantNumUpsertedServers {
t.Errorf("got %d upserted servers, wanted %d", lb.numUpsertedServers, test.wantNumUpsertedServers)
}
})
}
}
func MustParseURL(rawurl string) *url.URL {
u, err := url.Parse(rawurl)
if err != nil {
panic(fmt.Sprintf("failed to parse URL '%s': %s", rawurl, err))
}
return u
}

View File

@@ -2,32 +2,45 @@ package main
import (
"crypto/tls"
"errors"
"net/http"
"os"
"os/exec"
"time"
"github.com/go-check/check"
"errors"
"github.com/containous/traefik/integration/utils"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
// ACME test suites (using libcompose)
type AcmeSuite struct {
BaseSuite
boulderIP string
}
// Acme tests configuration
type AcmeTestCase struct {
onDemand bool
traefikConfFilePath string
domainToCheck string
}
// Domain to check
const acmeDomain = "traefik.acme.wtf"
// Wildcard domain to chekc
const wildcardDomain = "*.acme.wtf"
func (s *AcmeSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "boulder")
s.composeProject.Start(c)
boulderHost := s.composeProject.Container(c, "boulder").NetworkSettings.IPAddress
s.boulderIP = s.composeProject.Container(c, "boulder").NetworkSettings.IPAddress
// wait for boulder
err := utils.Try(120*time.Second, func() error {
resp, err := http.Get("http://" + boulderHost + ":4000/directory")
resp, err := http.Get("http://" + s.boulderIP + ":4000/directory")
if err != nil {
return err
}
@@ -47,9 +60,48 @@ func (s *AcmeSuite) TearDownSuite(c *check.C) {
}
}
func (s *AcmeSuite) TestRetrieveAcmeCertificate(c *check.C) {
boulderHost := s.composeProject.Container(c, "boulder").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/acme/acme.toml", struct{ BoulderHost string }{boulderHost})
// Test OnDemand option with none provided certificate
func (s *AcmeSuite) TestOnDemandRetrieveAcmeCertificate(c *check.C) {
aTestCase := AcmeTestCase{
traefikConfFilePath: "fixtures/acme/acme.toml",
onDemand: true,
domainToCheck: acmeDomain}
s.retrieveAcmeCertificate(c, aTestCase)
}
// Test OnHostRule option with none provided certificate
func (s *AcmeSuite) TestOnHostRuleRetrieveAcmeCertificate(c *check.C) {
aTestCase := AcmeTestCase{
traefikConfFilePath: "fixtures/acme/acme.toml",
onDemand: false,
domainToCheck: acmeDomain}
s.retrieveAcmeCertificate(c, aTestCase)
}
// Test OnDemand option with a wildcard provided certificate
func (s *AcmeSuite) TestOnDemandRetrieveAcmeCertificateWithWildcard(c *check.C) {
aTestCase := AcmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_provided.toml",
onDemand: true,
domainToCheck: wildcardDomain}
s.retrieveAcmeCertificate(c, aTestCase)
}
// Test onHostRule option with a wildcard provided certificate
func (s *AcmeSuite) TestOnHostRuleRetrieveAcmeCertificateWithWildcard(c *check.C) {
aTestCase := AcmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_provided.toml",
onDemand: false,
domainToCheck: wildcardDomain}
s.retrieveAcmeCertificate(c, aTestCase)
}
// Doing an HTTPS request and test the response certificate
func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, a AcmeTestCase) {
file := s.adaptFile(c, a.traefikConfFilePath, struct {
BoulderHost string
OnDemand, OnHostRule bool
}{s.boulderIP, a.onDemand, !a.onDemand})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
err := cmd.Start()
@@ -77,16 +129,32 @@ func (s *AcmeSuite) TestRetrieveAcmeCertificate(c *check.C) {
tr = &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
ServerName: "traefik.acme.wtf",
ServerName: acmeDomain,
},
}
client = &http.Client{Transport: tr}
req, _ := http.NewRequest("GET", "https://127.0.0.1:5001/", nil)
req.Host = "traefik.acme.wtf"
req.Header.Set("Host", "traefik.acme.wtf")
req.Host = acmeDomain
req.Header.Set("Host", acmeDomain)
req.Header.Set("Accept", "*/*")
resp, err := client.Do(req)
var resp *http.Response
// Retry to send a Request which uses the LE generated certificate
err = utils.Try(60*time.Second, func() error {
resp, err = client.Do(req)
// /!\ If connection is not closed, SSLHandshake will only be done during the first trial /!\
req.Close = true
if err != nil {
return err
} else if resp.TLS.PeerCertificates[0].Subject.CommonName != a.domainToCheck {
return errors.New("Domain " + resp.TLS.PeerCertificates[0].Subject.CommonName + " found in place of " + a.domainToCheck)
}
return nil
})
c.Assert(err, checker.IsNil)
// Check Domain into response certificate
c.Assert(resp.TLS.PeerCertificates[0].Subject.CommonName, checker.Equals, a.domainToCheck)
// Expected a 200
c.Assert(resp.StatusCode, checker.Equals, 200)
}

View File

@@ -26,7 +26,7 @@ func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) {
defer cmd.Process.Kill()
output := b.Bytes()
c.Assert(string(output), checker.Contains, "Near line 0 (last key parsed ''): Bare keys cannot contain '{'")
c.Assert(string(output), checker.Contains, "Near line 0 (last key parsed ''): bare keys cannot contain '{'")
}
func (s *SimpleSuite) TestSimpleDefaultConfig(c *check.C) {
@@ -70,7 +70,7 @@ func (s *SimpleSuite) TestDefaultEntryPoints(c *check.C) {
defer cmd.Process.Kill()
output := b.Bytes()
c.Assert(string(output), checker.Contains, "\\\"DefaultEntryPoints\\\":[\\\"http\\\"]")
c.Assert(string(output), checker.Contains, "\"DefaultEntryPoints\":[\"http\"]")
}
func (s *SimpleSuite) TestPrintHelp(c *check.C) {

View File

@@ -1,26 +1,25 @@
package main
import (
"context"
"errors"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"sync"
"time"
"context"
"github.com/containous/staert"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/provider"
"github.com/docker/libkv"
"github.com/docker/libkv/store"
"github.com/docker/libkv/store/consul"
"github.com/go-check/check"
"errors"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/provider"
checker "github.com/vdemeester/shakers"
"io/ioutil"
"os"
"strings"
"sync"
)
// Consul test suites (using libcompose)

View File

@@ -0,0 +1,181 @@
package main
import (
"errors"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/types"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
type DynamoDBSuite struct {
BaseSuite
}
type DynamoDBItem struct {
ID string `dynamodbav:"id"`
Name string `dynamodbav:"name"`
}
type DynamoDBBackendItem struct {
DynamoDBItem
Backend types.Backend `dynamodbav:"backend"`
}
type DynamoDBFrontendItem struct {
DynamoDBItem
Frontend types.Frontend `dynamodbav:"frontend"`
}
func (s *DynamoDBSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "dynamodb")
s.composeProject.Start(c)
dynamoURL := "http://" + s.composeProject.Container(c, "dynamo").NetworkSettings.IPAddress + ":8000"
config := &aws.Config{
Region: aws.String("us-east-1"),
Credentials: credentials.NewStaticCredentials("id", "secret", ""),
Endpoint: aws.String(dynamoURL),
}
var sess *session.Session
err := utils.Try(60*time.Second, func() error {
_, err := session.NewSession(config)
if err != nil {
return err
}
sess = session.New(config)
return nil
})
svc := dynamodb.New(sess)
// create dynamodb table
params := &dynamodb.CreateTableInput{
AttributeDefinitions: []*dynamodb.AttributeDefinition{
{
AttributeName: aws.String("id"),
AttributeType: aws.String("S"),
},
},
KeySchema: []*dynamodb.KeySchemaElement{
{
AttributeName: aws.String("id"),
KeyType: aws.String("HASH"),
},
},
ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
ReadCapacityUnits: aws.Int64(1),
WriteCapacityUnits: aws.Int64(1),
},
TableName: aws.String("traefik"),
}
_, err = svc.CreateTable(params)
if err != nil {
c.Error(err)
return
}
// load config into dynamodb
whoami1 := "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80"
whoami2 := "http://" + s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress + ":80"
whoami3 := "http://" + s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress + ":80"
backend := DynamoDBBackendItem{
Backend: types.Backend{
Servers: map[string]types.Server{
"whoami1": {
URL: whoami1,
},
"whoami2": {
URL: whoami2,
},
"whoami3": {
URL: whoami3,
},
},
},
DynamoDBItem: DynamoDBItem{
ID: "whoami_backend",
Name: "whoami",
},
}
frontend := DynamoDBFrontendItem{
Frontend: types.Frontend{
EntryPoints: []string{
"http",
},
Backend: "whoami",
Routes: map[string]types.Route{
"hostRule": {
Rule: "Host:test.traefik.io",
},
},
},
DynamoDBItem: DynamoDBItem{
ID: "whoami_frontend",
Name: "whoami",
},
}
backendAttributeValue, err := dynamodbattribute.MarshalMap(backend)
c.Assert(err, checker.IsNil)
frontendAttributeValue, err := dynamodbattribute.MarshalMap(frontend)
c.Assert(err, checker.IsNil)
putParams := &dynamodb.PutItemInput{
Item: backendAttributeValue,
TableName: aws.String("traefik"),
}
_, err = svc.PutItem(putParams)
c.Assert(err, checker.IsNil)
putParams = &dynamodb.PutItemInput{
Item: frontendAttributeValue,
TableName: aws.String("traefik"),
}
_, err = svc.PutItem(putParams)
c.Assert(err, checker.IsNil)
}
func (s *DynamoDBSuite) TestSimpleConfiguration(c *check.C) {
dynamoURL := "http://" + s.composeProject.Container(c, "dynamo").NetworkSettings.IPAddress + ":8000"
file := s.adaptFile(c, "fixtures/dynamodb/simple.toml", struct{ DynamoURL string }{dynamoURL})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = utils.TryRequest("http://127.0.0.1:8081/api/providers", 120*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Host:test.traefik.io") {
return errors.New("incorrect traefik config")
}
return nil
})
c.Assert(err, checker.IsNil)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8080", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.traefik.io"
response, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
}
func (s *DynamoDBSuite) TearDownSuite(c *check.C) {
if s.composeProject != nil {
s.composeProject.Stop(c)
}
}

View File

@@ -0,0 +1,37 @@
# How to generate the self-signed wildcard certificate
```bash
#!/usr/bin/env bash
# Specify where we will install
# the wildcard certificate
SSL_DIR="./ssl"
# Set the wildcarded domain
# we want to use
DOMAIN="*.acme.wtf"
# A blank passphrase
PASSPHRASE=""
# Set our CSR variables
SUBJ="
C=FR
ST=MP
O=
localityName=Toulouse
commonName=$DOMAIN
organizationalUnitName=Traefik
emailAddress=
"
# Create our SSL directory
# in case it doesn't exist
sudo mkdir -p "$SSL_DIR"
# Generate our Private Key, CSR and Certificate
sudo openssl genrsa -out "$SSL_DIR/wildcard.key" 2048
sudo openssl req -new -subj "$(echo -n "$SUBJ" | tr "\n" "/")" -key "$SSL_DIR/wildcard.key" -out "$SSL_DIR/wildcard.csr" -passin pass:$PASSPHRASE
sudo openssl x509 -req -days 3650 -in "$SSL_DIR/wildcard.csr" -signkey "$SSL_DIR/wildcard.key" -out "$SSL_DIR/wildcard.crt"
sudo rm -f "$SSL_DIR/wildcard.csr"
```

View File

@@ -14,7 +14,8 @@ defaultEntryPoints = ["http", "https"]
email = "test@traefik.io"
storage = "/dev/null"
entryPoint = "https"
onDemand = true
onDemand = {{.OnDemand}}
OnHostRule = {{.OnHostRule}}
caServer = "http://{{.BoulderHost}}:4000/directory"
[file]

View File

@@ -0,0 +1,35 @@
logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":8080"
[entryPoints.https]
address = ":5001"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
CertFile = "fixtures/acme/ssl/wildcard.crt"
KeyFile = "fixtures/acme/ssl/wildcard.key"
[acme]
email = "test@traefik.io"
storage = "/dev/null"
entryPoint = "https"
onDemand = {{.OnDemand}}
OnHostRule = {{.OnHostRule}}
caServer = "http://{{.BoulderHost}}:4000/directory"
[file]
[backends]
[backends.backend]
[backends.backend.servers.server1]
url = "http://127.0.0.1:9010"
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.test]
rule = "Host:traefik.acme.wtf"

View File

@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDJDCCAgwCCQCS90TE7NuTqzANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJG
UjELMAkGA1UECAwCTVAxETAPBgNVBAcMCFRvdWxvdXNlMRMwEQYDVQQDDAoqLmFj
bWUud3RmMRAwDgYDVQQLDAdUcmFlZmlrMB4XDTE3MDYyMzE0NTE0MVoXDTI3MDYy
MTE0NTE0MVowVDELMAkGA1UEBhMCRlIxCzAJBgNVBAgMAk1QMREwDwYDVQQHDAhU
b3Vsb3VzZTETMBEGA1UEAwwKKi5hY21lLnd0ZjEQMA4GA1UECwwHVHJhZWZpazCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODqsVCLhauFZPhPXqZDIKST
wqoJST+jO5O/WmA7oC4S6JlecRoNsHAXyddd3cQW3yZqB0ryOHrMOpMX0PPXf3jS
OOXoXA6xsq+RXlR4hDrBkOrj/LR/g62Eiuj2JVO2uy6tKJIetSB/Wzl6OgRkY/um
EXIc7zQS81/QKg+pg7Z4AYJht5J88nOFHJ3RspUMaH1vJ6LhH3MOUkgFj+I1OiqX
Tnkd7EDWbkYxAJa0xI2qbmY5VYv8dsIUN+IlPFDtBt87Fc2qv5dQkOz11FDYxWnz
+kxX6+MESLBaTvJjXvG+bzTfh9xCExFQFiN+Us0JuLX8HKQ4MqWL2IiVLsko2osC
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAl2jTX2yzUpiufrJ6WtZjKIAH8GF817hS
dWvt2eyLrBPvllMUj8zqCE5uNVUDVuXQvOhOyx+3zZzfcgfYqbTD8G8amNWcSiRA
vonoOn1p1pW2OonSi32h3qv5i4gCyh/6cBneYi03lkQ7uLCsJK9+dXTAvoKL6s23
IXhZGS0Qkvs4vkORA2MX9tyJdyfCCaCx3GpPCGkKrKJ8ePTEvq1ZE2xdhERnV5pz
L1PRY2QthXXVjMz7AXw0gkHvAbtrKVKR1Tv4ZK34bFBh/kyGAjkcn0zdeFKITqTF
tCoXWEArmiRqGuXwbqU3mEA9Cv6aMM+0YX89K2InhOnBU80OWs0uMQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA4OqxUIuFq4Vk+E9epkMgpJPCqglJP6M7k79aYDugLhLomV5x
Gg2wcBfJ113dxBbfJmoHSvI4esw6kxfQ89d/eNI45ehcDrGyr5FeVHiEOsGQ6uP8
tH+DrYSK6PYlU7a7Lq0okh61IH9bOXo6BGRj+6YRchzvNBLzX9AqD6mDtngBgmG3
knzyc4UcndGylQxofW8nouEfcw5SSAWP4jU6KpdOeR3sQNZuRjEAlrTEjapuZjlV
i/x2whQ34iU8UO0G3zsVzaq/l1CQ7PXUUNjFafP6TFfr4wRIsFpO8mNe8b5vNN+H
3EITEVAWI35SzQm4tfwcpDgypYvYiJUuySjaiwIDAQABAoIBAQCs9Ex9v4x+pQlL
2NzTxXLom6dp0dI92WwK5W696Zv3UhsDNRiMDFLNH73amxfZnizjAU2yWCkOZNX2
Hq5TlDc11ZJjWRbRRdw+He8HzdUAybCCr+a3dgbv+6hGFGIHydCOyCEWm/50ivq/
bDoI/pnT/ZQUyCM5TAlSeGSfvp7GRHi9v3HOl85H1Pn2Dvyk9gj4y3BIFrKuv8fJ
o6aEzlfgWGROCzshU2m8fB9P0B4hWDlJsc1D01sW60zhjLo9+XoWznmw5mczz7sc
S5sdDh47rSJsNRuFd7YDjeLzJWPqLrKVB5nn6nRbvrnBqhfsknkO4VIXhmEMSs1u
RMYOJ9ShAoGBAPinA6ktIeez1t5IsfxGwbCeZzFI1suZqZeX6ezNKaMpeykyAPuh
CqN7H+a4NCKsinsgHJowU98ckHeAsQ22s7R8dFZhyxEXkcBawY2soK29eq2aJHnY
lqKOwjOA7wgElRHwLkNFniQ5lKFPMly8a9NVAqg+Th/J3uR+7wE2t+b1AoGBAOeQ
H/vVkdaNB2ovnCxMh+OfxpcjkfF6KnD2jpn/TKsbR5BtnrtyRLc5+qt52D0CEgSy
qU3zrsZebShej3OIBPrEwIcPN+LezaxnLMf9RXdOde+wWrQLWLkShJaSTwSoGqZB
fcO0/sc1lzhGxm++ByP5mWbHr/VM9IdTQQH5Bct/AoGBAMhmOrIXeNL4Az2FU0Vi
dWp2T+7NqKfRAXj264Z5V4xzuxpZfadPhHZ7nhth7Erhyn4vRD4UoxQXPmvB4XCP
Bkh5YX3ZNUNiPorL2mDnd1xvcLcHm0xEfisnaWb/DCbnIomhjHeVXT4O1jYn0Qwi
o7hgNFMKXAaMuUJo9xGAWzkdAoGASxC4nY2tOiz7k1udt+qTPqHj4cjhHbOpoHb8
4UUWmH0+ZL50b3Vqey8raH0WMSjDqIw2QBPXu2yO3EBTJnOYkaZIdz/isQPjDplf
tfEPnM5tgubbcHQhLdWn75u8S9km0nB2kYPR98gSnmarGzwx2mKmbOAc1Vs+BcRi
VX5hd4cCgYAubBq0VsFT0KVU3Rva3dgPR1K5bp4r4hE5cGXm4HvLiOgv995CwPy1
27eONF9GN7hvjI6C17jA1Gyx5sN0QrsMv/1BZqiGaragMOPXFD+tVecWuKH4lZQi
VbKTOWHlGkrDCpiYWpfetQAjouj+0c6d+wigcoC8e5dwxBPI2f3rGw==
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,16 @@
defaultEntryPoints = ["http"]
logLevel = "DEBUG"
[entryPoints]
[entryPoints.http]
address = ":8080"
[dynamodb]
AccessKeyID = "key"
SecretAccessKey = "secret"
Endpoint = "{{.DynamoURL}}"
Region = "us-east-1"
[web]
address = ":8081"

View File

@@ -13,7 +13,7 @@ logLevel = "DEBUG"
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
url = "/health"
path = "/health"
interval = "1s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"

View File

@@ -0,0 +1,24 @@
defaultEntryPoints = ["http"]
logLevel = "DEBUG"
[entryPoints]
[entryPoints.http]
address = ":8000"
[web]
address = ":8080"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "{{ .WebsocketServer }}"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path:/ws"

View File

@@ -1,4 +1,4 @@
hash: c53f57a45247b08a91f127ece494d49f1b7fee8c5f75be87ab12e27aa92d065f
hash: afc00e3aa064550eed7ff6a98b4eced543fe41e84894f1ac0ec25adf06354ec7
updated: 2016-11-17T16:23:56.727970904Z
imports:
- name: github.com/cenk/backoff
@@ -286,6 +286,7 @@ testImports:
- context
- proxy
- publicsuffix
- websocket
- name: golang.org/x/sys
version: 9c60d1c508f5134d1ca726b4641db998f2523357
subpackages:

View File

@@ -29,5 +29,6 @@ testImport:
- package: golang.org/x/net
subpackages:
- context
- websocket
- package: github.com/spf13/pflag
version: 5644820622454e71517561946e3d94b9f9db6842

View File

@@ -16,16 +16,16 @@ import (
checker "github.com/vdemeester/shakers"
)
// HealchCheck test suites (using libcompose)
type HealchCheckSuite struct{ BaseSuite }
// HealthCheck test suites (using libcompose)
type HealthCheckSuite struct{ BaseSuite }
func (s *HealchCheckSuite) SetUpSuite(c *check.C) {
func (s *HealthCheckSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "healthcheck")
s.composeProject.Start(c)
}
func (s *HealchCheckSuite) TestSimpleConfiguration(c *check.C) {
func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
whoami1Host := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2Host := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress

View File

@@ -14,6 +14,8 @@ import (
"github.com/containous/traefik/integration/utils"
"github.com/go-check/check"
"bytes"
compose "github.com/libkermit/compose/check"
checker "github.com/vdemeester/shakers"
)
@@ -27,6 +29,7 @@ func init() {
check.Suite(&AccessLogSuite{})
check.Suite(&HTTPSSuite{})
check.Suite(&FileSuite{})
check.Suite(&HealthCheckSuite{})
check.Suite(&DockerSuite{})
check.Suite(&ConsulSuite{})
check.Suite(&ConsulCatalogSuite{})
@@ -36,6 +39,8 @@ func init() {
check.Suite(&MesosSuite{})
check.Suite(&EurekaSuite{})
check.Suite(&AcmeSuite{})
check.Suite(&DynamoDBSuite{})
check.Suite(&WebsocketSuite{})
}
var traefikBinary = "../dist/traefik"
@@ -69,6 +74,18 @@ func (s *BaseSuite) createComposeProject(c *check.C, name string) {
s.composeProject = compose.CreateProject(c, projectName, composeFile)
}
func withConfigFile(file string) string {
return "--configFile=" + file
}
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
cmd := exec.Command(traefikBinary, args...)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
return cmd, &out
}
func (s *BaseSuite) traefikCmd(c *check.C, args ...string) (*exec.Cmd, string) {
cmd, out, err := utils.RunCommand(traefikBinary, args...)
c.Assert(err, checker.IsNil, check.Commentf("Fail to run %s with %v", traefikBinary, args))

View File

@@ -39,6 +39,6 @@ bmysql:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
log_driver: none
brabbitmq:
image: rabbitmq:3
image: rabbitmq:3-alpine
environment:
RABBITMQ_NODE_IP_ADDRESS: "0.0.0.0"

View File

@@ -12,6 +12,6 @@ consul:
- "8302"
- "8302/udp"
nginx:
image: nginx
image: nginx:alpine
ports:
- "8881:80"

View File

@@ -12,6 +12,6 @@ consul:
- "8302"
- "8302/udp"
nginx:
image: nginx
image: nginx:alpine
ports:
- "8881:80"

View File

@@ -0,0 +1,16 @@
dynamo:
image: deangiberson/aws-dynamodb-local
command: -sharedDb
ports:
- "8000:8000"
expose:
- "8000"
whoami1:
image: emilevauge/whoami
whoami2:
image: emilevauge/whoami
whoami3:
image: emilevauge/whoami

View File

@@ -1,20 +1,20 @@
nginx1:
image: nginx
image: nginx:alpine
ports:
- "8881:80"
nginx2:
image: nginx
image: nginx:alpine
ports:
- "8882:80"
nginx3:
image: nginx
image: nginx:alpine
ports:
- "8883:80"
nginx4:
image: nginx
image: nginx:alpine
ports:
- "8884:80"
nginx5:
image: nginx
image: nginx:alpine
ports:
- "8885:80"

View File

@@ -0,0 +1,357 @@
package eureka
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path"
"time"
"strings"
)
const (
defaultBufferSize = 10
UP = "UP"
DOWN = "DOWN"
STARTING = "STARTING"
)
type Config struct {
CertFile string `json:"certFile"`
KeyFile string `json:"keyFile"`
CaCertFile []string `json:"caCertFiles"`
DialTimeout time.Duration `json:"timeout"`
Consistency string `json:"consistency"`
}
type Client struct {
Config Config `json:"config"`
Cluster *Cluster `json:"cluster"`
httpClient *http.Client
persistence io.Writer
cURLch chan string
// CheckRetry can be used to control the policy for failed requests
// and modify the cluster if needed.
// The client calls it before sending requests again, and
// stops retrying if CheckRetry returns some error. The cases that
// this function needs to handle include no response and unexpected
// http status code of response.
// If CheckRetry is nil, client will call the default one
// `DefaultCheckRetry`.
// Argument cluster is the eureka.Cluster object that these requests have been made on.
// Argument numReqs is the number of http.Requests that have been made so far.
// Argument lastResp is the http.Responses from the last request.
// Argument err is the reason of the failure.
CheckRetry func(cluster *Cluster, numReqs int,
lastResp http.Response, err error) error
}
// NewClient create a basic client that is configured to be used
// with the given machine list.
func NewClient(machines []string) *Client {
config := Config{
// default timeout is one second
DialTimeout: time.Second,
}
client := &Client{
Cluster: NewCluster(machines),
Config: config,
}
client.initHTTPClient()
return client
}
// NewTLSClient create a basic client with TLS configuration
func NewTLSClient(machines []string, cert string, key string, caCerts []string) (*Client, error) {
// overwrite the default machine to use https
if len(machines) == 0 {
machines = []string{"https://127.0.0.1:4001"}
}
config := Config{
// default timeout is one second
DialTimeout: time.Second,
CertFile: cert,
KeyFile: key,
CaCertFile: make([]string, 0),
}
client := &Client{
Cluster: NewCluster(machines),
Config: config,
}
err := client.initHTTPSClient(cert, key)
if err != nil {
return nil, err
}
for _, caCert := range caCerts {
if err := client.AddRootCA(caCert); err != nil {
return nil, err
}
}
return client, nil
}
// NewClientFromFile creates a client from a given file path.
// The given file is expected to use the JSON format.
func NewClientFromFile(fpath string) (*Client, error) {
fi, err := os.Open(fpath)
if err != nil {
return nil, err
}
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
return NewClientFromReader(fi)
}
// NewClientFromReader creates a Client configured from a given reader.
// The configuration is expected to use the JSON format.
func NewClientFromReader(reader io.Reader) (*Client, error) {
c := new(Client)
b, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
err = json.Unmarshal(b, c)
if err != nil {
return nil, err
}
if c.Config.CertFile == "" {
c.initHTTPClient()
} else {
err = c.initHTTPSClient(c.Config.CertFile, c.Config.KeyFile)
}
if err != nil {
return nil, err
}
for _, caCert := range c.Config.CaCertFile {
if err := c.AddRootCA(caCert); err != nil {
return nil, err
}
}
return c, nil
}
// Override the Client's HTTP Transport object
func (c *Client) SetTransport(tr *http.Transport) {
c.httpClient.Transport = tr
}
// initHTTPClient initializes a HTTP client for eureka client
func (c *Client) initHTTPClient() {
tr := &http.Transport{
Dial: c.dial,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
c.httpClient = &http.Client{Transport: tr}
}
// initHTTPClient initializes a HTTPS client for eureka client
func (c *Client) initHTTPSClient(cert, key string) error {
if cert == "" || key == "" {
return errors.New("Require both cert and key path")
}
tlsCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return err
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{tlsCert},
InsecureSkipVerify: true,
}
tr := &http.Transport{
TLSClientConfig: tlsConfig,
Dial: c.dial,
}
c.httpClient = &http.Client{Transport: tr}
return nil
}
// Sets the DialTimeout value
func (c *Client) SetDialTimeout(d time.Duration) {
c.Config.DialTimeout = d
}
// AddRootCA adds a root CA cert for the eureka client
func (c *Client) AddRootCA(caCert string) error {
if c.httpClient == nil {
return errors.New("Client has not been initialized yet!")
}
certBytes, err := ioutil.ReadFile(caCert)
if err != nil {
return err
}
tr, ok := c.httpClient.Transport.(*http.Transport)
if !ok {
panic("AddRootCA(): Transport type assert should not fail")
}
if tr.TLSClientConfig.RootCAs == nil {
caCertPool := x509.NewCertPool()
ok = caCertPool.AppendCertsFromPEM(certBytes)
if ok {
tr.TLSClientConfig.RootCAs = caCertPool
}
tr.TLSClientConfig.InsecureSkipVerify = false
} else {
ok = tr.TLSClientConfig.RootCAs.AppendCertsFromPEM(certBytes)
}
if !ok {
err = errors.New("Unable to load caCert")
}
c.Config.CaCertFile = append(c.Config.CaCertFile, caCert)
return err
}
// SetCluster updates cluster information using the given machine list.
func (c *Client) SetCluster(machines []string) bool {
success := c.internalSyncCluster(machines)
return success
}
func (c *Client) GetCluster() []string {
return c.Cluster.Machines
}
// SyncCluster updates the cluster information using the internal machine list.
func (c *Client) SyncCluster() bool {
return c.internalSyncCluster(c.Cluster.Machines)
}
// internalSyncCluster syncs cluster information using the given machine list.
func (c *Client) internalSyncCluster(machines []string) bool {
for _, machine := range machines {
httpPath := c.createHttpPath(machine, "machines")
resp, err := c.httpClient.Get(httpPath)
if err != nil {
// try another machine in the cluster
continue
} else {
b, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
// try another machine in the cluster
continue
}
// update Machines List
c.Cluster.updateFromStr(string(b))
// update leader
// the first one in the machine list is the leader
c.Cluster.switchLeader(0)
logger.Debug("sync.machines " + strings.Join(c.Cluster.Machines, ", "))
return true
}
}
return false
}
// createHttpPath creates a complete HTTP URL.
// serverName should contain both the host name and a port number, if any.
func (c *Client) createHttpPath(serverName string, _path string) string {
u, err := url.Parse(serverName)
if err != nil {
panic(err)
}
u.Path = path.Join(u.Path, _path)
if u.Scheme == "" {
u.Scheme = "http"
}
return u.String()
}
// dial attempts to open a TCP connection to the provided address, explicitly
// enabling keep-alives with a one-second interval.
func (c *Client) dial(network, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(network, addr, c.Config.DialTimeout)
if err != nil {
return nil, err
}
tcpConn, ok := conn.(*net.TCPConn)
if !ok {
return nil, errors.New("Failed type-assertion of net.Conn as *net.TCPConn")
}
// Keep TCP alive to check whether or not the remote machine is down
if err = tcpConn.SetKeepAlive(true); err != nil {
return nil, err
}
if err = tcpConn.SetKeepAlivePeriod(time.Second); err != nil {
return nil, err
}
return tcpConn, nil
}
// MarshalJSON implements the Marshaller interface
// as defined by the standard JSON package.
func (c *Client) MarshalJSON() ([]byte, error) {
b, err := json.Marshal(struct {
Config Config `json:"config"`
Cluster *Cluster `json:"cluster"`
}{
Config: c.Config,
Cluster: c.Cluster,
})
if err != nil {
return nil, err
}
return b, nil
}
// UnmarshalJSON implements the Unmarshaller interface
// as defined by the standard JSON package.
func (c *Client) UnmarshalJSON(b []byte) error {
temp := struct {
Config Config `json:"config"`
Cluster *Cluster `json:"cluster"`
}{}
err := json.Unmarshal(b, &temp)
if err != nil {
return err
}
c.Cluster = temp.Cluster
c.Config = temp.Config
return nil
}

View File

@@ -0,0 +1,51 @@
package eureka
import (
"net/url"
"strings"
)
type Cluster struct {
Leader string `json:"leader"`
Machines []string `json:"machines"`
}
func NewCluster(machines []string) *Cluster {
// if an empty slice was sent in then just assume HTTP 4001 on localhost
if len(machines) == 0 {
machines = []string{"http://127.0.0.1:4001"}
}
// default leader and machines
return &Cluster{
Leader: machines[0],
Machines: machines,
}
}
// switchLeader switch the current leader to machines[num]
func (cl *Cluster) switchLeader(num int) {
logger.Debug("switch.leader[from %v to %v]",
cl.Leader, cl.Machines[num])
cl.Leader = cl.Machines[num]
}
func (cl *Cluster) updateFromStr(machines string) {
cl.Machines = strings.Split(machines, ", ")
}
func (cl *Cluster) updateLeader(leader string) {
logger.Debug("update.leader[%s,%s]", cl.Leader, leader)
cl.Leader = leader
}
func (cl *Cluster) updateLeaderFromURL(u *url.URL) {
var leader string
if u.Scheme == "" {
leader = "http://" + u.Host
} else {
leader = u.Scheme + "://" + u.Host
}
cl.updateLeader(leader)
}

View File

@@ -0,0 +1,21 @@
package eureka
import (
"github.com/ArthurHlt/gominlog"
"log"
)
var logger *gominlog.MinLog
func GetLogger() *log.Logger {
return logger.GetLogger()
}
func SetLogger(loggerLog *log.Logger) {
logger.SetLogger(loggerLog)
}
func init() {
// Default logger uses the go default log.
logger = gominlog.NewClassicMinLogWithPackageName("go-eureka-client")
}

View File

@@ -0,0 +1,10 @@
package eureka
import "strings"
func (c *Client) UnregisterInstance(appId, instanceId string) error {
values := []string{"apps", appId, instanceId}
path := strings.Join(values, "/")
_, err := c.Delete(path)
return err
}

View File

@@ -0,0 +1,48 @@
package eureka
import (
"encoding/json"
"fmt"
)
const (
ErrCodeEurekaNotReachable = 501
)
var (
errorMap = map[int]string{
ErrCodeEurekaNotReachable: "All the given peers are not reachable",
}
)
type EurekaError struct {
ErrorCode int `json:"errorCode"`
Message string `json:"message"`
Cause string `json:"cause,omitempty"`
Index uint64 `json:"index"`
}
func (e EurekaError) Error() string {
return fmt.Sprintf("%v: %v (%v) [%v]", e.ErrorCode, e.Message, e.Cause, e.Index)
}
func newError(errorCode int, cause string, index uint64) *EurekaError {
return &EurekaError{
ErrorCode: errorCode,
Message: errorMap[errorCode],
Cause: cause,
Index: index,
}
}
func handleError(b []byte) error {
eurekaErr := new(EurekaError)
err := json.Unmarshal(b, eurekaErr)
if err != nil {
logger.Warning("cannot unmarshal eureka error: %v", err)
return err
}
return eurekaErr
}

View File

@@ -0,0 +1,38 @@
package eureka
import (
"encoding/xml"
"strings"
)
func (c *Client) GetApplications() (*Applications, error) {
response, err := c.Get("apps");
if err != nil {
return nil, err
}
var applications *Applications = new(Applications)
err = xml.Unmarshal(response.Body, applications)
return applications, err
}
func (c *Client) GetApplication(appId string) (*Application, error) {
values := []string{"apps", appId}
path := strings.Join(values, "/")
response, err := c.Get(path);
if err != nil {
return nil, err
}
var application *Application = new(Application)
err = xml.Unmarshal(response.Body, application)
return application, err
}
func (c *Client) GetInstance(appId, instanceId string) (*InstanceInfo, error) {
values := []string{"apps", appId, instanceId}
path := strings.Join(values, "/")
response, err := c.Get(path);
if err != nil {
return nil, err
}
var instance *InstanceInfo = new(InstanceInfo)
err = xml.Unmarshal(response.Body, instance)
return instance, err
}

View File

@@ -0,0 +1,95 @@
package eureka
import (
"encoding/xml"
"encoding/json"
"regexp"
)
type MetaData struct {
Map map[string]string
Class string
}
type Vraw struct {
Content []byte `xml:",innerxml"`
Class string `xml:"class,attr" json:"@class"`
}
func (s *MetaData) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
var attributes []xml.Attr = make([]xml.Attr, 0)
if s.Class != "" {
attributes = append(attributes, xml.Attr{
Name: xml.Name{
Local: "class",
},
Value: s.Class,
})
}
start.Attr = attributes
tokens := []xml.Token{start}
for key, value := range s.Map {
t := xml.StartElement{Name: xml.Name{"", key}}
tokens = append(tokens, t, xml.CharData(value), xml.EndElement{t.Name})
}
tokens = append(tokens, xml.EndElement{
Name: start.Name,
})
for _, t := range tokens {
err := e.EncodeToken(t)
if err != nil {
return err
}
}
// flush to ensure tokens are written
err := e.Flush()
if err != nil {
return err
}
return nil
}
func (s *MetaData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
s.Map = make(map[string]string)
vraw := &Vraw{}
d.DecodeElement(vraw, &start)
dataInString := string(vraw.Content)
regex, err := regexp.Compile("\\s*<([^<>]+)>([^<>]+)</[^<>]+>\\s*")
if err != nil {
return err
}
subMatches := regex.FindAllStringSubmatch(dataInString, -1)
for _, subMatch := range subMatches {
s.Map[subMatch[1]] = subMatch[2]
}
s.Class = vraw.Class
return nil
}
func (s *MetaData) MarshalJSON() ([]byte, error) {
mapIt := make(map[string]string)
for key, value := range s.Map {
mapIt[key] = value
}
if s.Class != "" {
mapIt["@class"] = s.Class
}
return json.Marshal(mapIt)
}
func (s *MetaData) UnmarshalJSON(data []byte) error {
dataUnmarshal := make(map[string]string)
err := json.Unmarshal(data, dataUnmarshal)
s.Map = dataUnmarshal
if val, ok := s.Map["@class"]; ok {
s.Class = val
delete(s.Map, "@class")
}
return err
}

View File

@@ -0,0 +1,21 @@
package eureka
import (
"encoding/json"
"strings"
)
func (c *Client) RegisterInstance(appId string, instanceInfo *InstanceInfo) error {
values := []string{"apps", appId}
path := strings.Join(values, "/")
instance := &Instance{
Instance: instanceInfo,
}
body, err := json.Marshal(instance)
if err != nil {
return err
}
_, err = c.Post(path, body)
return err
}

View File

@@ -0,0 +1,10 @@
package eureka
import "strings"
func (c *Client) SendHeartbeat(appId, instanceId string) error {
values := []string{"apps", appId, instanceId}
path := strings.Join(values, "/")
_, err := c.Put(path, nil)
return err
}

View File

@@ -0,0 +1,437 @@
package eureka
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"sync"
"time"
"strconv"
)
// Errors introduced by handling requests
var (
ErrRequestCancelled = errors.New("sending request is cancelled")
)
type RawRequest struct {
method string
relativePath string
body []byte
cancel <-chan bool
}
type Applications struct {
VersionsDelta int `xml:"versions__delta"`
AppsHashcode string `xml:"apps__hashcode"`
Applications []Application `xml:"application,omitempty"`
}
type Application struct {
Name string `xml:"name"`
Instances []InstanceInfo `xml:"instance"`
}
type Instance struct {
Instance *InstanceInfo `xml:"instance" json:"instance"`
}
type Port struct {
Port int `xml:",chardata" json:"$"`
Enabled bool `xml:"enabled,attr" json:"@enabled"`
}
type InstanceInfo struct {
HostName string `xml:"hostName" json:"hostName"`
HomePageUrl string `xml:"homePageUrl,omitempty" json:"homePageUrl,omitempty"`
StatusPageUrl string `xml:"statusPageUrl" json:"statusPageUrl"`
HealthCheckUrl string `xml:"healthCheckUrl,omitempty" json:"healthCheckUrl,omitempty"`
App string `xml:"app" json:"app"`
IpAddr string `xml:"ipAddr" json:"ipAddr"`
VipAddress string `xml:"vipAddress" json:"vipAddress"`
secureVipAddress string `xml:"secureVipAddress,omitempty" json:"secureVipAddress,omitempty"`
Status string `xml:"status" json:"status"`
Port *Port `xml:"port,omitempty" json:"port,omitempty"`
SecurePort *Port `xml:"securePort,omitempty" json:"securePort,omitempty"`
DataCenterInfo *DataCenterInfo `xml:"dataCenterInfo" json:"dataCenterInfo"`
LeaseInfo *LeaseInfo `xml:"leaseInfo,omitempty" json:"leaseInfo,omitempty"`
Metadata *MetaData `xml:"metadata,omitempty" json:"metadata,omitempty"`
IsCoordinatingDiscoveryServer bool `xml:"isCoordinatingDiscoveryServer,omitempty" json:"isCoordinatingDiscoveryServer,omitempty"`
LastUpdatedTimestamp int `xml:"lastUpdatedTimestamp,omitempty" json:"lastUpdatedTimestamp,omitempty"`
LastDirtyTimestamp int `xml:"lastDirtyTimestamp,omitempty" json:"lastDirtyTimestamp,omitempty"`
ActionType string `xml:"actionType,omitempty" json:"actionType,omitempty"`
Overriddenstatus string `xml:"overriddenstatus,omitempty" json:"overriddenstatus,omitempty"`
CountryId int `xml:"countryId,omitempty" json:"countryId,omitempty"`
}
type DataCenterInfo struct {
Name string `xml:"name" json:"name"`
Class string `xml:"class,attr" json:"@class"`
Metadata DataCenterMetadata `xml:"metadata,omitempty" json:"metadata,omitempty"`
}
type DataCenterMetadata struct {
AmiLaunchIndex string `xml:"ami-launch-index,omitempty" json:"ami-launch-index,omitempty"`
LocalHostname string `xml:"local-hostname,omitempty" json:"local-hostname,omitempty"`
AvailabilityZone string `xml:"availability-zone,omitempty" json:"availability-zone,omitempty"`
InstanceId string `xml:"instance-id,omitempty" json:"instance-id,omitempty"`
PublicIpv4 string `xml:"public-ipv4,omitempty" json:"public-ipv4,omitempty"`
PublicHostname string `xml:"public-hostname,omitempty" json:"public-hostname,omitempty"`
AmiManifestPath string `xml:"ami-manifest-path,omitempty" json:"ami-manifest-path,omitempty"`
LocalIpv4 string `xml:"local-ipv4,omitempty" json:"local-ipv4,omitempty"`
Hostname string `xml:"hostname,omitempty" json:"hostname,omitempty"`
AmiId string `xml:"ami-id,omitempty" json:"ami-id,omitempty"`
InstanceType string `xml:"instance-type,omitempty" json:"instance-type,omitempty"`
}
type LeaseInfo struct {
EvictionDurationInSecs uint `xml:"evictionDurationInSecs,omitempty" json:"evictionDurationInSecs,omitempty"`
RenewalIntervalInSecs int `xml:"renewalIntervalInSecs,omitempty" json:"renewalIntervalInSecs,omitempty"`
DurationInSecs int `xml:"durationInSecs,omitempty" json:"durationInSecs,omitempty"`
RegistrationTimestamp int `xml:"registrationTimestamp,omitempty" json:"registrationTimestamp,omitempty"`
LastRenewalTimestamp int `xml:"lastRenewalTimestamp,omitempty" json:"lastRenewalTimestamp,omitempty"`
EvictionTimestamp int `xml:"evictionTimestamp,omitempty" json:"evictionTimestamp,omitempty"`
ServiceUpTimestamp int `xml:"serviceUpTimestamp,omitempty" json:"serviceUpTimestamp,omitempty"`
}
func NewRawRequest(method, relativePath string, body []byte, cancel <-chan bool) *RawRequest {
return &RawRequest{
method: method,
relativePath: relativePath,
body: body,
cancel: cancel,
}
}
func NewInstanceInfo(hostName, app, ip string, port int, ttl uint, isSsl bool) *InstanceInfo {
dataCenterInfo := &DataCenterInfo{
Name: "MyOwn",
}
leaseInfo := &LeaseInfo{
EvictionDurationInSecs: ttl,
}
instanceInfo := &InstanceInfo{
HostName: hostName,
App: app,
IpAddr: ip,
Status: UP,
DataCenterInfo: dataCenterInfo,
LeaseInfo: leaseInfo,
Metadata: nil,
}
stringPort := ""
if (port != 80 && port != 443) {
stringPort = ":" + strconv.Itoa(port)
}
var protocol string = "http"
if (isSsl) {
protocol = "https"
instanceInfo.secureVipAddress = protocol + "://" + hostName + stringPort
instanceInfo.SecurePort = &Port{
Port: port,
Enabled: true,
}
}else {
instanceInfo.VipAddress = protocol + "://" + hostName + stringPort
instanceInfo.Port = &Port{
Port: port,
Enabled: true,
}
}
instanceInfo.StatusPageUrl = protocol + "://" + hostName + stringPort + "/info"
return instanceInfo
}
// getCancelable issues a cancelable GET request
func (c *Client) getCancelable(endpoint string,
cancel <-chan bool) (*RawResponse, error) {
logger.Debug("get %s [%s]", endpoint, c.Cluster.Leader)
p := endpoint
req := NewRawRequest("GET", p, nil, cancel)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// get issues a GET request
func (c *Client) Get(endpoint string) (*RawResponse, error) {
return c.getCancelable(endpoint, nil)
}
// put issues a PUT request
func (c *Client) Put(endpoint string, body []byte) (*RawResponse, error) {
logger.Debug("put %s, %s, [%s]", endpoint, body, c.Cluster.Leader)
p := endpoint
req := NewRawRequest("PUT", p, body, nil)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// post issues a POST request
func (c *Client) Post(endpoint string, body []byte) (*RawResponse, error) {
logger.Debug("post %s, %s, [%s]", endpoint, body, c.Cluster.Leader)
p := endpoint
req := NewRawRequest("POST", p, body, nil)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// delete issues a DELETE request
func (c *Client) Delete(endpoint string) (*RawResponse, error) {
logger.Debug("delete %s [%s]", endpoint, c.Cluster.Leader)
p := endpoint
req := NewRawRequest("DELETE", p, nil, nil)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
var req *http.Request
var resp *http.Response
var httpPath string
var err error
var respBody []byte
var numReqs = 1
checkRetry := c.CheckRetry
if checkRetry == nil {
checkRetry = DefaultCheckRetry
}
cancelled := make(chan bool, 1)
reqLock := new(sync.Mutex)
if rr.cancel != nil {
cancelRoutine := make(chan bool)
defer close(cancelRoutine)
go func() {
select {
case <-rr.cancel:
cancelled <- true
logger.Debug("send.request is cancelled")
case <-cancelRoutine:
return
}
// Repeat canceling request until this thread is stopped
// because we have no idea about whether it succeeds.
for {
reqLock.Lock()
c.httpClient.Transport.(*http.Transport).CancelRequest(req)
reqLock.Unlock()
select {
case <-time.After(100 * time.Millisecond):
case <-cancelRoutine:
return
}
}
}()
}
// If we connect to a follower and consistency is required, retry until
// we connect to a leader
sleep := 25 * time.Millisecond
maxSleep := time.Second
for attempt := 0;; attempt++ {
if attempt > 0 {
select {
case <-cancelled:
return nil, ErrRequestCancelled
case <-time.After(sleep):
sleep = sleep * 2
if sleep > maxSleep {
sleep = maxSleep
}
}
}
logger.Debug("Connecting to eureka: attempt %d for %s", attempt + 1, rr.relativePath)
httpPath = c.getHttpPath(false, rr.relativePath)
logger.Debug("send.request.to %s | method %s", httpPath, rr.method)
req, err := func() (*http.Request, error) {
reqLock.Lock()
defer reqLock.Unlock()
if req, err = http.NewRequest(rr.method, httpPath, bytes.NewReader(rr.body)); err != nil {
return nil, err
}
req.Header.Set("Content-Type",
"application/json")
return req, nil
}()
if err != nil {
return nil, err
}
resp, err = c.httpClient.Do(req)
defer func() {
if resp != nil {
resp.Body.Close()
}
}()
// If the request was cancelled, return ErrRequestCancelled directly
select {
case <-cancelled:
return nil, ErrRequestCancelled
default:
}
numReqs++
// network error, change a machine!
if err != nil {
logger.Error("network error: %v", err.Error())
lastResp := http.Response{}
if checkErr := checkRetry(c.Cluster, numReqs, lastResp, err); checkErr != nil {
return nil, checkErr
}
c.Cluster.switchLeader(attempt % len(c.Cluster.Machines))
continue
}
// if there is no error, it should receive response
logger.Debug("recv.response.from "+httpPath)
if validHttpStatusCode[resp.StatusCode] {
// try to read byte code and break the loop
respBody, err = ioutil.ReadAll(resp.Body)
if err == nil {
logger.Debug("recv.success "+ httpPath)
break
}
// ReadAll error may be caused due to cancel request
select {
case <-cancelled:
return nil, ErrRequestCancelled
default:
}
if err == io.ErrUnexpectedEOF {
// underlying connection was closed prematurely, probably by timeout
// TODO: empty body or unexpectedEOF can cause http.Transport to get hosed;
// this allows the client to detect that and take evasive action. Need
// to revisit once code.google.com/p/go/issues/detail?id=8648 gets fixed.
respBody = []byte{}
break
}
}
// if resp is TemporaryRedirect, set the new leader and retry
if resp.StatusCode == http.StatusTemporaryRedirect {
u, err := resp.Location()
if err != nil {
logger.Warning("%v", err)
} else {
// Update cluster leader based on redirect location
// because it should point to the leader address
c.Cluster.updateLeaderFromURL(u)
logger.Debug("recv.response.relocate "+ u.String())
}
resp.Body.Close()
continue
}
if checkErr := checkRetry(c.Cluster, numReqs, *resp,
errors.New("Unexpected HTTP status code")); checkErr != nil {
return nil, checkErr
}
resp.Body.Close()
}
r := &RawResponse{
StatusCode: resp.StatusCode,
Body: respBody,
Header: resp.Header,
}
return r, nil
}
// DefaultCheckRetry defines the retrying behaviour for bad HTTP requests
// If we have retried 2 * machine number, stop retrying.
// If status code is InternalServerError, sleep for 200ms.
func DefaultCheckRetry(cluster *Cluster, numReqs int, lastResp http.Response,
err error) error {
if numReqs >= 2 * len(cluster.Machines) {
return newError(ErrCodeEurekaNotReachable,
"Tried to connect to each peer twice and failed", 0)
}
code := lastResp.StatusCode
if code == http.StatusInternalServerError {
time.Sleep(time.Millisecond * 200)
}
logger.Warning("bad response status code %d", code)
return nil
}
func (c *Client) getHttpPath(random bool, s ...string) string {
var machine string
if random {
machine = c.Cluster.Machines[rand.Intn(len(c.Cluster.Machines))]
} else {
machine = c.Cluster.Leader
}
fullPath := machine
for _, seg := range s {
fullPath += "/" + seg
}
return fullPath
}
// buildValues builds a url.Values map according to the given value and ttl
func buildValues(value string, ttl uint64) url.Values {
v := url.Values{}
if value != "" {
v.Set("value", value)
}
if ttl > 0 {
v.Set("ttl", fmt.Sprintf("%v", ttl))
}
return v
}

View File

@@ -0,0 +1,21 @@
package eureka
import "net/http"
type RawResponse struct {
StatusCode int
Body []byte
Header http.Header
}
var (
validHttpStatusCode = map[int]bool{
http.StatusNoContent: true,
http.StatusCreated: true,
http.StatusOK: true,
http.StatusBadRequest: true,
http.StatusNotFound: true,
http.StatusPreconditionFailed: true,
http.StatusForbidden: true,
}
)

View File

@@ -0,0 +1,3 @@
package eureka
const version = "v2"

View File

@@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) 2015 Arthur Halet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
The Software should rather be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,185 @@
package gominlog
import (
"log"
"os"
"fmt"
"runtime"
"github.com/daviddengcn/go-colortext"
"regexp"
"strings"
"io"
)
type Level int
const (
Loff = Level(^uint(0) >> 1)
Lsevere = Level(1000)
Lerror = Level(900)
Lwarning = Level(800)
Linfo = Level(700)
Ldebug = Level(600)
Lall = Level(-Loff - 1)
)
type MinLog struct {
log *log.Logger
level Level
packageName string
isColorized bool
}
func NewClassicMinLog() *MinLog {
minLog := &MinLog{}
logWriter := os.Stdout
flags := log.Lshortfile | log.Ldate | log.Ltime
minLog.log = log.New(logWriter, "", flags)
minLog.isColorized = true
minLog.packageName = ""
minLog.level = Lall
return minLog
}
func NewClassicMinLogWithPackageName(packageName string) *MinLog {
minLog := NewClassicMinLog()
minLog.SetPackageName(packageName)
return minLog
}
func NewMinLog(appName string, level Level, withColor bool, flag int) *MinLog {
minLog := &MinLog{}
logWriter := os.Stdout
minLog.log = log.New(logWriter, "", flag)
minLog.isColorized = withColor
minLog.packageName = appName
minLog.level = level
return minLog
}
func NewMinLogWithLogger(packageName string, level Level, withColor bool, logger *log.Logger) *MinLog {
minLog := &MinLog{}
minLog.log = logger
minLog.isColorized = withColor
minLog.packageName = packageName
minLog.level = level
return minLog
}
func (this *MinLog) GetLevel() Level {
return Level(this.level)
}
func (this *MinLog) SetWriter(writer io.Writer) {
this.log.SetOutput(writer)
}
func (this *MinLog) SetLevel(level Level) {
this.level = level
}
func (this *MinLog) SetPackageName(newPackageName string) {
this.packageName = newPackageName
}
func (this *MinLog) GetPackageName() string {
return this.packageName
}
func (this *MinLog) SetLogger(l *log.Logger) {
this.log = l
}
func (this *MinLog) WithColor(isColorized bool) {
this.isColorized = isColorized
}
func (this *MinLog) IsColorized() bool {
return this.isColorized
}
func (this *MinLog) GetLogger() *log.Logger {
return this.log
}
func (this *MinLog) logMessage(typeLog string, colorFg ct.Color, colorBg ct.Color, args ...interface{}) {
var text string
msg := ""
flags := this.log.Flags()
if (log.Lshortfile | flags) == flags {
msg += this.trace()
this.log.SetFlags(flags - log.Lshortfile)
}
text, ok := args[0].(string);
if !ok {
panic("Firt argument should be a string")
}
if len(args) > 1 {
newArgs := args[1:]
msg += typeLog + ": " + fmt.Sprintf(text, newArgs...)
}else {
msg += typeLog + ": " + text
}
this.writeMsgInLogger(msg, colorFg, colorBg)
this.log.SetFlags(flags)
}
func (this *MinLog) writeMsgInLogger(msg string, colorFg ct.Color, colorBg ct.Color) {
if this.isColorized && colorFg > 0 {
ct.Foreground(colorFg, false)
}
if this.isColorized && colorBg > 0 {
ct.ChangeColor(colorFg, false, colorBg, false)
}
this.log.Print(msg)
if this.isColorized {
ct.ResetColor()
}
}
func (this *MinLog) Error(args ...interface{}) {
if this.level > Lerror {
return
}
this.logMessage("ERROR", ct.Red, 0, args...)
}
func (this *MinLog) Severe(args ...interface{}) {
if this.level > Lsevere {
return
}
this.logMessage("SEVERE", ct.Red, ct.Yellow, args...)
}
func (this *MinLog) Debug(args ...interface{}) {
if this.level > Ldebug {
return
}
this.logMessage("DEBUG", ct.Blue, 0, args...)
}
func (this *MinLog) Info(args ...interface{}) {
if this.level > Linfo {
return
}
this.logMessage("INFO", ct.Cyan, 0, args...)
}
func (this *MinLog) Warning(args ...interface{}) {
if this.level > Lwarning {
return
}
this.logMessage("WARNING", ct.Yellow, 0, args...)
}
func (this *MinLog) trace() string {
var shortFile string
pc := make([]uintptr, 10)
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[2])
file, line := f.FileLine(pc[2])
if this.packageName == "" {
execFileSplit := strings.Split(os.Args[0], "/")
this.packageName = execFileSplit[len(execFileSplit) - 1]
}
regex, err := regexp.Compile(regexp.QuoteMeta(this.packageName) + "/(.*)")
if err != nil {
panic(err)
}
subMatch := regex.FindStringSubmatch(file)
if len(subMatch) < 2 {
fileSplit := strings.Split(file, "/")
shortFile = fileSplit[len(fileSplit) - 1]
}else {
shortFile = subMatch[1]
}
return fmt.Sprintf("/%s/%s:%d ", this.packageName, shortFile, line)
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,188 @@
package ansiterm
const LogEnv = "DEBUG_TERMINAL"
// ANSI constants
// References:
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
// -- http://vt100.net/emu/dec_ansi_parser
// -- http://vt100.net/emu/vt500_parser.svg
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
// -- http://www.inwap.com/pdp10/ansicode.txt
const (
// ECMA-48 Set Graphics Rendition
// Note:
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
ANSI_SGR_RESET = 0
ANSI_SGR_BOLD = 1
ANSI_SGR_DIM = 2
_ANSI_SGR_ITALIC = 3
ANSI_SGR_UNDERLINE = 4
_ANSI_SGR_BLINKSLOW = 5
_ANSI_SGR_BLINKFAST = 6
ANSI_SGR_REVERSE = 7
_ANSI_SGR_INVISIBLE = 8
_ANSI_SGR_LINETHROUGH = 9
_ANSI_SGR_FONT_00 = 10
_ANSI_SGR_FONT_01 = 11
_ANSI_SGR_FONT_02 = 12
_ANSI_SGR_FONT_03 = 13
_ANSI_SGR_FONT_04 = 14
_ANSI_SGR_FONT_05 = 15
_ANSI_SGR_FONT_06 = 16
_ANSI_SGR_FONT_07 = 17
_ANSI_SGR_FONT_08 = 18
_ANSI_SGR_FONT_09 = 19
_ANSI_SGR_FONT_10 = 20
_ANSI_SGR_DOUBLEUNDERLINE = 21
ANSI_SGR_BOLD_DIM_OFF = 22
_ANSI_SGR_ITALIC_OFF = 23
ANSI_SGR_UNDERLINE_OFF = 24
_ANSI_SGR_BLINK_OFF = 25
_ANSI_SGR_RESERVED_00 = 26
ANSI_SGR_REVERSE_OFF = 27
_ANSI_SGR_INVISIBLE_OFF = 28
_ANSI_SGR_LINETHROUGH_OFF = 29
ANSI_SGR_FOREGROUND_BLACK = 30
ANSI_SGR_FOREGROUND_RED = 31
ANSI_SGR_FOREGROUND_GREEN = 32
ANSI_SGR_FOREGROUND_YELLOW = 33
ANSI_SGR_FOREGROUND_BLUE = 34
ANSI_SGR_FOREGROUND_MAGENTA = 35
ANSI_SGR_FOREGROUND_CYAN = 36
ANSI_SGR_FOREGROUND_WHITE = 37
_ANSI_SGR_RESERVED_01 = 38
ANSI_SGR_FOREGROUND_DEFAULT = 39
ANSI_SGR_BACKGROUND_BLACK = 40
ANSI_SGR_BACKGROUND_RED = 41
ANSI_SGR_BACKGROUND_GREEN = 42
ANSI_SGR_BACKGROUND_YELLOW = 43
ANSI_SGR_BACKGROUND_BLUE = 44
ANSI_SGR_BACKGROUND_MAGENTA = 45
ANSI_SGR_BACKGROUND_CYAN = 46
ANSI_SGR_BACKGROUND_WHITE = 47
_ANSI_SGR_RESERVED_02 = 48
ANSI_SGR_BACKGROUND_DEFAULT = 49
// 50 - 65: Unsupported
ANSI_MAX_CMD_LENGTH = 4096
MAX_INPUT_EVENTS = 128
DEFAULT_WIDTH = 80
DEFAULT_HEIGHT = 24
ANSI_BEL = 0x07
ANSI_BACKSPACE = 0x08
ANSI_TAB = 0x09
ANSI_LINE_FEED = 0x0A
ANSI_VERTICAL_TAB = 0x0B
ANSI_FORM_FEED = 0x0C
ANSI_CARRIAGE_RETURN = 0x0D
ANSI_ESCAPE_PRIMARY = 0x1B
ANSI_ESCAPE_SECONDARY = 0x5B
ANSI_OSC_STRING_ENTRY = 0x5D
ANSI_COMMAND_FIRST = 0x40
ANSI_COMMAND_LAST = 0x7E
DCS_ENTRY = 0x90
CSI_ENTRY = 0x9B
OSC_STRING = 0x9D
ANSI_PARAMETER_SEP = ";"
ANSI_CMD_G0 = '('
ANSI_CMD_G1 = ')'
ANSI_CMD_G2 = '*'
ANSI_CMD_G3 = '+'
ANSI_CMD_DECPNM = '>'
ANSI_CMD_DECPAM = '='
ANSI_CMD_OSC = ']'
ANSI_CMD_STR_TERM = '\\'
KEY_CONTROL_PARAM_2 = ";2"
KEY_CONTROL_PARAM_3 = ";3"
KEY_CONTROL_PARAM_4 = ";4"
KEY_CONTROL_PARAM_5 = ";5"
KEY_CONTROL_PARAM_6 = ";6"
KEY_CONTROL_PARAM_7 = ";7"
KEY_CONTROL_PARAM_8 = ";8"
KEY_ESC_CSI = "\x1B["
KEY_ESC_N = "\x1BN"
KEY_ESC_O = "\x1BO"
FILL_CHARACTER = ' '
)
func getByteRange(start byte, end byte) []byte {
bytes := make([]byte, 0, 32)
for i := start; i <= end; i++ {
bytes = append(bytes, byte(i))
}
return bytes
}
var toGroundBytes = getToGroundBytes()
var executors = getExecuteBytes()
// SPACE 20+A0 hex Always and everywhere a blank space
// Intermediate 20-2F hex !"#$%&'()*+,-./
var intermeds = getByteRange(0x20, 0x2F)
// Parameters 30-3F hex 0123456789:;<=>?
// CSI Parameters 30-39, 3B hex 0123456789;
var csiParams = getByteRange(0x30, 0x3F)
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
var upperCase = getByteRange(0x40, 0x5F)
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
var lowerCase = getByteRange(0x60, 0x7E)
// Alphabetics 40-7E hex (all of upper and lower case)
var alphabetics = append(upperCase, lowerCase...)
var printables = getByteRange(0x20, 0x7F)
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
var escapeToGroundBytes = getEscapeToGroundBytes()
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
// byte ranges below
func getEscapeToGroundBytes() []byte {
escapeToGroundBytes := getByteRange(0x30, 0x4F)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
return escapeToGroundBytes
}
func getExecuteBytes() []byte {
executeBytes := getByteRange(0x00, 0x17)
executeBytes = append(executeBytes, 0x19)
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
return executeBytes
}
func getToGroundBytes() []byte {
groundBytes := []byte{0x18}
groundBytes = append(groundBytes, 0x1A)
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
groundBytes = append(groundBytes, 0x99)
groundBytes = append(groundBytes, 0x9A)
groundBytes = append(groundBytes, 0x9C)
return groundBytes
}
// Delete 7F hex Always and everywhere ignored
// C1 Control 80-9F hex 32 additional control characters
// G1 Displayable A1-FE hex 94 additional displayable characters
// Special A0+FF hex Same as SPACE and DELETE

View File

@@ -0,0 +1,7 @@
package ansiterm
type ansiContext struct {
currentChar byte
paramBuffer []byte
interBuffer []byte
}

View File

@@ -0,0 +1,49 @@
package ansiterm
type csiEntryState struct {
baseState
}
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
logger.Infof("CsiEntry::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
return csiState.parser.csiParam, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiEntryState) Transition(s state) error {
logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
case csiState.parser.csiParam:
switch {
case sliceContains(csiParams, csiState.parser.context.currentChar):
csiState.parser.collectParam()
case sliceContains(intermeds, csiState.parser.context.currentChar):
csiState.parser.collectInter()
}
}
return nil
}
func (csiState csiEntryState) Enter() error {
csiState.parser.clear()
return nil
}

View File

@@ -0,0 +1,38 @@
package ansiterm
type csiParamState struct {
baseState
}
func (csiState csiParamState) Handle(b byte) (s state, e error) {
logger.Infof("CsiParam::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
csiState.parser.collectParam()
return csiState, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiParamState) Transition(s state) error {
logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
}
return nil
}

View File

@@ -0,0 +1,36 @@
package ansiterm
type escapeIntermediateState struct {
baseState
}
func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
logger.Infof("escapeIntermediateState::Handle %#x", b)
nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(intermeds, b):
return escState, escState.parser.collectInter()
case sliceContains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeIntermediateToGroundBytes, b):
return escState.parser.ground, nil
}
return escState, nil
}
func (escState escapeIntermediateState) Transition(s state) error {
logger.Infof("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
escState.baseState.Transition(s)
switch s {
case escState.parser.ground:
return escState.parser.escDispatch()
}
return nil
}

View File

@@ -0,0 +1,47 @@
package ansiterm
type escapeState struct {
baseState
}
func (escState escapeState) Handle(b byte) (s state, e error) {
logger.Infof("escapeState::Handle %#x", b)
nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case b == ANSI_ESCAPE_SECONDARY:
return escState.parser.csiEntry, nil
case b == ANSI_OSC_STRING_ENTRY:
return escState.parser.oscString, nil
case sliceContains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeToGroundBytes, b):
return escState.parser.ground, nil
case sliceContains(intermeds, b):
return escState.parser.escapeIntermediate, nil
}
return escState, nil
}
func (escState escapeState) Transition(s state) error {
logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name())
escState.baseState.Transition(s)
switch s {
case escState.parser.ground:
return escState.parser.escDispatch()
case escState.parser.escapeIntermediate:
return escState.parser.collectInter()
}
return nil
}
func (escState escapeState) Enter() error {
escState.parser.clear()
return nil
}

View File

@@ -0,0 +1,90 @@
package ansiterm
type AnsiEventHandler interface {
// Print
Print(b byte) error
// Execute C0 commands
Execute(b byte) error
// CUrsor Up
CUU(int) error
// CUrsor Down
CUD(int) error
// CUrsor Forward
CUF(int) error
// CUrsor Backward
CUB(int) error
// Cursor to Next Line
CNL(int) error
// Cursor to Previous Line
CPL(int) error
// Cursor Horizontal position Absolute
CHA(int) error
// Vertical line Position Absolute
VPA(int) error
// CUrsor Position
CUP(int, int) error
// Horizontal and Vertical Position (depends on PUM)
HVP(int, int) error
// Text Cursor Enable Mode
DECTCEM(bool) error
// Origin Mode
DECOM(bool) error
// 132 Column Mode
DECCOLM(bool) error
// Erase in Display
ED(int) error
// Erase in Line
EL(int) error
// Insert Line
IL(int) error
// Delete Line
DL(int) error
// Insert Character
ICH(int) error
// Delete Character
DCH(int) error
// Set Graphics Rendition
SGR([]int) error
// Pan Down
SU(int) error
// Pan Up
SD(int) error
// Device Attributes
DA([]string) error
// Set Top and Bottom Margins
DECSTBM(int, int) error
// Index
IND() error
// Reverse Index
RI() error
// Flush updates from previous commands
Flush() error
}

View File

@@ -0,0 +1,24 @@
package ansiterm
type groundState struct {
baseState
}
func (gs groundState) Handle(b byte) (s state, e error) {
gs.parser.context.currentChar = b
nextState, err := gs.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(printables, b):
return gs, gs.parser.print()
case sliceContains(executors, b):
return gs, gs.parser.execute()
}
return gs, nil
}

View File

@@ -0,0 +1,31 @@
package ansiterm
type oscStringState struct {
baseState
}
func (oscState oscStringState) Handle(b byte) (s state, e error) {
logger.Infof("OscString::Handle %#x", b)
nextState, err := oscState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case isOscStringTerminator(b):
return oscState.parser.ground, nil
}
return oscState, nil
}
// See below for OSC string terminators for linux
// http://man7.org/linux/man-pages/man4/console_codes.4.html
func isOscStringTerminator(b byte) bool {
if b == ANSI_BEL || b == 0x5C {
return true
}
return false
}

View File

@@ -0,0 +1,136 @@
package ansiterm
import (
"errors"
"io/ioutil"
"os"
"github.com/Sirupsen/logrus"
)
var logger *logrus.Logger
type AnsiParser struct {
currState state
eventHandler AnsiEventHandler
context *ansiContext
csiEntry state
csiParam state
dcsEntry state
escape state
escapeIntermediate state
error state
ground state
oscString state
stateMap []state
}
func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser {
logFile := ioutil.Discard
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
logFile, _ = os.Create("ansiParser.log")
}
logger = &logrus.Logger{
Out: logFile,
Formatter: new(logrus.TextFormatter),
Level: logrus.InfoLevel,
}
parser := &AnsiParser{
eventHandler: evtHandler,
context: &ansiContext{},
}
parser.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: parser}}
parser.csiParam = csiParamState{baseState{name: "CsiParam", parser: parser}}
parser.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: parser}}
parser.escape = escapeState{baseState{name: "Escape", parser: parser}}
parser.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: parser}}
parser.error = errorState{baseState{name: "Error", parser: parser}}
parser.ground = groundState{baseState{name: "Ground", parser: parser}}
parser.oscString = oscStringState{baseState{name: "OscString", parser: parser}}
parser.stateMap = []state{
parser.csiEntry,
parser.csiParam,
parser.dcsEntry,
parser.escape,
parser.escapeIntermediate,
parser.error,
parser.ground,
parser.oscString,
}
parser.currState = getState(initialState, parser.stateMap)
logger.Infof("CreateParser: parser %p", parser)
return parser
}
func getState(name string, states []state) state {
for _, el := range states {
if el.Name() == name {
return el
}
}
return nil
}
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
for i, b := range bytes {
if err := ap.handle(b); err != nil {
return i, err
}
}
return len(bytes), ap.eventHandler.Flush()
}
func (ap *AnsiParser) handle(b byte) error {
ap.context.currentChar = b
newState, err := ap.currState.Handle(b)
if err != nil {
return err
}
if newState == nil {
logger.Warning("newState is nil")
return errors.New("New state of 'nil' is invalid.")
}
if newState != ap.currState {
if err := ap.changeState(newState); err != nil {
return err
}
}
return nil
}
func (ap *AnsiParser) changeState(newState state) error {
logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
// Exit old state
if err := ap.currState.Exit(); err != nil {
logger.Infof("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
return err
}
// Perform transition action
if err := ap.currState.Transition(newState); err != nil {
logger.Infof("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
return err
}
// Enter new state
if err := newState.Enter(); err != nil {
logger.Infof("Enter state '%s' failed with: '%v'", newState.Name(), err)
return err
}
ap.currState = newState
return nil
}

View File

@@ -0,0 +1,103 @@
package ansiterm
import (
"strconv"
)
func parseParams(bytes []byte) ([]string, error) {
paramBuff := make([]byte, 0, 0)
params := []string{}
for _, v := range bytes {
if v == ';' {
if len(paramBuff) > 0 {
// Completed parameter, append it to the list
s := string(paramBuff)
params = append(params, s)
paramBuff = make([]byte, 0, 0)
}
} else {
paramBuff = append(paramBuff, v)
}
}
// Last parameter may not be terminated with ';'
if len(paramBuff) > 0 {
s := string(paramBuff)
params = append(params, s)
}
logger.Infof("Parsed params: %v with length: %d", params, len(params))
return params, nil
}
func parseCmd(context ansiContext) (string, error) {
return string(context.currentChar), nil
}
func getInt(params []string, dflt int) int {
i := getInts(params, 1, dflt)[0]
logger.Infof("getInt: %v", i)
return i
}
func getInts(params []string, minCount int, dflt int) []int {
ints := []int{}
for _, v := range params {
i, _ := strconv.Atoi(v)
// Zero is mapped to the default value in VT100.
if i == 0 {
i = dflt
}
ints = append(ints, i)
}
if len(ints) < minCount {
remaining := minCount - len(ints)
for i := 0; i < remaining; i++ {
ints = append(ints, dflt)
}
}
logger.Infof("getInts: %v", ints)
return ints
}
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
switch param {
case "?3":
return ap.eventHandler.DECCOLM(set)
case "?6":
return ap.eventHandler.DECOM(set)
case "?25":
return ap.eventHandler.DECTCEM(set)
}
return nil
}
func (ap *AnsiParser) hDispatch(params []string) error {
if len(params) == 1 {
return ap.modeDispatch(params[0], true)
}
return nil
}
func (ap *AnsiParser) lDispatch(params []string) error {
if len(params) == 1 {
return ap.modeDispatch(params[0], false)
}
return nil
}
func getEraseParam(params []string) int {
param := getInt(params, 0)
if param < 0 || 3 < param {
param = 0
}
return param
}

View File

@@ -0,0 +1,122 @@
package ansiterm
import (
"fmt"
)
func (ap *AnsiParser) collectParam() error {
currChar := ap.context.currentChar
logger.Infof("collectParam %#x", currChar)
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
return nil
}
func (ap *AnsiParser) collectInter() error {
currChar := ap.context.currentChar
logger.Infof("collectInter %#x", currChar)
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
return nil
}
func (ap *AnsiParser) escDispatch() error {
cmd, _ := parseCmd(*ap.context)
intermeds := ap.context.interBuffer
logger.Infof("escDispatch currentChar: %#x", ap.context.currentChar)
logger.Infof("escDispatch: %v(%v)", cmd, intermeds)
switch cmd {
case "D": // IND
return ap.eventHandler.IND()
case "E": // NEL, equivalent to CRLF
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
if err == nil {
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
}
return err
case "M": // RI
return ap.eventHandler.RI()
}
return nil
}
func (ap *AnsiParser) csiDispatch() error {
cmd, _ := parseCmd(*ap.context)
params, _ := parseParams(ap.context.paramBuffer)
logger.Infof("csiDispatch: %v(%v)", cmd, params)
switch cmd {
case "@":
return ap.eventHandler.ICH(getInt(params, 1))
case "A":
return ap.eventHandler.CUU(getInt(params, 1))
case "B":
return ap.eventHandler.CUD(getInt(params, 1))
case "C":
return ap.eventHandler.CUF(getInt(params, 1))
case "D":
return ap.eventHandler.CUB(getInt(params, 1))
case "E":
return ap.eventHandler.CNL(getInt(params, 1))
case "F":
return ap.eventHandler.CPL(getInt(params, 1))
case "G":
return ap.eventHandler.CHA(getInt(params, 1))
case "H":
ints := getInts(params, 2, 1)
x, y := ints[0], ints[1]
return ap.eventHandler.CUP(x, y)
case "J":
param := getEraseParam(params)
return ap.eventHandler.ED(param)
case "K":
param := getEraseParam(params)
return ap.eventHandler.EL(param)
case "L":
return ap.eventHandler.IL(getInt(params, 1))
case "M":
return ap.eventHandler.DL(getInt(params, 1))
case "P":
return ap.eventHandler.DCH(getInt(params, 1))
case "S":
return ap.eventHandler.SU(getInt(params, 1))
case "T":
return ap.eventHandler.SD(getInt(params, 1))
case "c":
return ap.eventHandler.DA(params)
case "d":
return ap.eventHandler.VPA(getInt(params, 1))
case "f":
ints := getInts(params, 2, 1)
x, y := ints[0], ints[1]
return ap.eventHandler.HVP(x, y)
case "h":
return ap.hDispatch(params)
case "l":
return ap.lDispatch(params)
case "m":
return ap.eventHandler.SGR(getInts(params, 1, 0))
case "r":
ints := getInts(params, 2, 1)
top, bottom := ints[0], ints[1]
return ap.eventHandler.DECSTBM(top, bottom)
default:
logger.Errorf(fmt.Sprintf("Unsupported CSI command: '%s', with full context: %v", cmd, ap.context))
return nil
}
}
func (ap *AnsiParser) print() error {
return ap.eventHandler.Print(ap.context.currentChar)
}
func (ap *AnsiParser) clear() error {
ap.context = &ansiContext{}
return nil
}
func (ap *AnsiParser) execute() error {
return ap.eventHandler.Execute(ap.context.currentChar)
}

View File

@@ -0,0 +1,71 @@
package ansiterm
type stateID int
type state interface {
Enter() error
Exit() error
Handle(byte) (state, error)
Name() string
Transition(state) error
}
type baseState struct {
name string
parser *AnsiParser
}
func (base baseState) Enter() error {
return nil
}
func (base baseState) Exit() error {
return nil
}
func (base baseState) Handle(b byte) (s state, e error) {
switch {
case b == CSI_ENTRY:
return base.parser.csiEntry, nil
case b == DCS_ENTRY:
return base.parser.dcsEntry, nil
case b == ANSI_ESCAPE_PRIMARY:
return base.parser.escape, nil
case b == OSC_STRING:
return base.parser.oscString, nil
case sliceContains(toGroundBytes, b):
return base.parser.ground, nil
}
return nil, nil
}
func (base baseState) Name() string {
return base.name
}
func (base baseState) Transition(s state) error {
if s == base.parser.ground {
execBytes := []byte{0x18}
execBytes = append(execBytes, 0x1A)
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
execBytes = append(execBytes, 0x99)
execBytes = append(execBytes, 0x9A)
if sliceContains(execBytes, base.parser.context.currentChar) {
return base.parser.execute()
}
}
return nil
}
type dcsEntryState struct {
baseState
}
type errorState struct {
baseState
}

View File

@@ -0,0 +1,21 @@
package ansiterm
import (
"strconv"
)
func sliceContains(bytes []byte, b byte) bool {
for _, v := range bytes {
if v == b {
return true
}
}
return false
}
func convertBytesToInteger(bytes []byte) int {
s := string(bytes)
i, _ := strconv.Atoi(s)
return i
}

View File

@@ -0,0 +1,182 @@
// +build windows
package winterm
import (
"fmt"
"os"
"strconv"
"strings"
"syscall"
"github.com/Azure/go-ansiterm"
)
// Windows keyboard constants
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
const (
VK_PRIOR = 0x21 // PAGE UP key
VK_NEXT = 0x22 // PAGE DOWN key
VK_END = 0x23 // END key
VK_HOME = 0x24 // HOME key
VK_LEFT = 0x25 // LEFT ARROW key
VK_UP = 0x26 // UP ARROW key
VK_RIGHT = 0x27 // RIGHT ARROW key
VK_DOWN = 0x28 // DOWN ARROW key
VK_SELECT = 0x29 // SELECT key
VK_PRINT = 0x2A // PRINT key
VK_EXECUTE = 0x2B // EXECUTE key
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
VK_INSERT = 0x2D // INS key
VK_DELETE = 0x2E // DEL key
VK_HELP = 0x2F // HELP key
VK_F1 = 0x70 // F1 key
VK_F2 = 0x71 // F2 key
VK_F3 = 0x72 // F3 key
VK_F4 = 0x73 // F4 key
VK_F5 = 0x74 // F5 key
VK_F6 = 0x75 // F6 key
VK_F7 = 0x76 // F7 key
VK_F8 = 0x77 // F8 key
VK_F9 = 0x78 // F9 key
VK_F10 = 0x79 // F10 key
VK_F11 = 0x7A // F11 key
VK_F12 = 0x7B // F12 key
RIGHT_ALT_PRESSED = 0x0001
LEFT_ALT_PRESSED = 0x0002
RIGHT_CTRL_PRESSED = 0x0004
LEFT_CTRL_PRESSED = 0x0008
SHIFT_PRESSED = 0x0010
NUMLOCK_ON = 0x0020
SCROLLLOCK_ON = 0x0040
CAPSLOCK_ON = 0x0080
ENHANCED_KEY = 0x0100
)
type ansiCommand struct {
CommandBytes []byte
Command string
Parameters []string
IsSpecial bool
}
func newAnsiCommand(command []byte) *ansiCommand {
if isCharacterSelectionCmdChar(command[1]) {
// Is Character Set Selection commands
return &ansiCommand{
CommandBytes: command,
Command: string(command),
IsSpecial: true,
}
}
// last char is command character
lastCharIndex := len(command) - 1
ac := &ansiCommand{
CommandBytes: command,
Command: string(command[lastCharIndex]),
IsSpecial: false,
}
// more than a single escape
if lastCharIndex != 0 {
start := 1
// skip if double char escape sequence
if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
start++
}
// convert this to GetNextParam method
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
}
return ac
}
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
if index < 0 || index >= len(ac.Parameters) {
return defaultValue
}
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
if err != nil {
return defaultValue
}
return int16(param)
}
func (ac *ansiCommand) String() string {
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
bytesToHex(ac.CommandBytes),
ac.Command,
strings.Join(ac.Parameters, "\",\""))
}
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
func isAnsiCommandChar(b byte) bool {
switch {
case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
return true
case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
// non-CSI escape sequence terminator
return true
case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
// String escape sequence terminator
return true
}
return false
}
func isXtermOscSequence(command []byte, current byte) bool {
return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
}
func isCharacterSelectionCmdChar(b byte) bool {
return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
}
// bytesToHex converts a slice of bytes to a human-readable string.
func bytesToHex(b []byte) string {
hex := make([]string, len(b))
for i, ch := range b {
hex[i] = fmt.Sprintf("%X", ch)
}
return strings.Join(hex, "")
}
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
// the passed min / max range.
func ensureInRange(n int16, min int16, max int16) int16 {
if n < min {
return min
} else if n > max {
return max
} else {
return n
}
}
func GetStdFile(nFile int) (*os.File, uintptr) {
var file *os.File
switch nFile {
case syscall.STD_INPUT_HANDLE:
file = os.Stdin
case syscall.STD_OUTPUT_HANDLE:
file = os.Stdout
case syscall.STD_ERROR_HANDLE:
file = os.Stderr
default:
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
}
fd, err := syscall.GetStdHandle(nFile)
if err != nil {
panic(fmt.Errorf("Invalid standard handle indentifier: %v -- %v", nFile, err))
}
return file, uintptr(fd)
}

View File

@@ -0,0 +1,322 @@
// +build windows
package winterm
import (
"fmt"
"syscall"
"unsafe"
)
//===========================================================================================================
// IMPORTANT NOTE:
//
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
// variables) the pointers reference *before* the API completes.
//
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
// require unsafe pointers.
//
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
// the garbage collector the variables remain in use if:
//
// -- The value is not a pointer (e.g., int32, struct)
// -- The value is not referenced by the method after passing the pointer to Windows
//
// See http://golang.org/doc/go1.3.
//===========================================================================================================
var (
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
)
// Windows Console constants
const (
// Console modes
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_LINE_INPUT = 0x0002
ENABLE_ECHO_INPUT = 0x0004
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_INSERT_MODE = 0x0020
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_EXTENDED_FLAGS = 0x0080
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
// Character attributes
// Note:
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
// Clearing all foreground or background colors results in black; setting all creates white.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
FOREGROUND_BLUE uint16 = 0x0001
FOREGROUND_GREEN uint16 = 0x0002
FOREGROUND_RED uint16 = 0x0004
FOREGROUND_INTENSITY uint16 = 0x0008
FOREGROUND_MASK uint16 = 0x000F
BACKGROUND_BLUE uint16 = 0x0010
BACKGROUND_GREEN uint16 = 0x0020
BACKGROUND_RED uint16 = 0x0040
BACKGROUND_INTENSITY uint16 = 0x0080
BACKGROUND_MASK uint16 = 0x00F0
COMMON_LVB_MASK uint16 = 0xFF00
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
COMMON_LVB_UNDERSCORE uint16 = 0x8000
// Input event types
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
KEY_EVENT = 0x0001
MOUSE_EVENT = 0x0002
WINDOW_BUFFER_SIZE_EVENT = 0x0004
MENU_EVENT = 0x0008
FOCUS_EVENT = 0x0010
// WaitForSingleObject return codes
WAIT_ABANDONED = 0x00000080
WAIT_FAILED = 0xFFFFFFFF
WAIT_SIGNALED = 0x0000000
WAIT_TIMEOUT = 0x00000102
// WaitForSingleObject wait duration
WAIT_INFINITE = 0xFFFFFFFF
WAIT_ONE_SECOND = 1000
WAIT_HALF_SECOND = 500
WAIT_QUARTER_SECOND = 250
)
// Windows API Console types
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
type (
CHAR_INFO struct {
UnicodeChar uint16
Attributes uint16
}
CONSOLE_CURSOR_INFO struct {
Size uint32
Visible int32
}
CONSOLE_SCREEN_BUFFER_INFO struct {
Size COORD
CursorPosition COORD
Attributes uint16
Window SMALL_RECT
MaximumWindowSize COORD
}
COORD struct {
X int16
Y int16
}
SMALL_RECT struct {
Left int16
Top int16
Right int16
Bottom int16
}
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
INPUT_RECORD struct {
EventType uint16
KeyEvent KEY_EVENT_RECORD
}
KEY_EVENT_RECORD struct {
KeyDown int32
RepeatCount uint16
VirtualKeyCode uint16
VirtualScanCode uint16
UnicodeChar uint16
ControlKeyState uint32
}
WINDOW_BUFFER_SIZE struct {
Size COORD
}
)
// boolToBOOL converts a Go bool into a Windows int32.
func boolToBOOL(f bool) int32 {
if f {
return int32(1)
} else {
return int32(0)
}
}
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
return checkError(r1, r2, err)
}
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
return checkError(r1, r2, err)
}
// SetConsoleCursorPosition location of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
}
// GetConsoleMode gets the console mode for given file descriptor
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
return mode, err
}
// SetConsoleMode sets the console mode for given file descriptor
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
func SetConsoleMode(handle uintptr, mode uint32) error {
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
use(mode)
return checkError(r1, r2, err)
}
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
info := CONSOLE_SCREEN_BUFFER_INFO{}
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
if err != nil {
return nil, err
}
return &info, nil
}
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
use(scrollRect)
use(clipRect)
use(destOrigin)
use(char)
return checkError(r1, r2, err)
}
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
}
// SetConsoleTextAttribute sets the attributes of characters written to the
// console screen buffer by the WriteFile or WriteConsole function.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
use(attribute)
return checkError(r1, r2, err)
}
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
// Note that the size and location must be within and no larger than the backing console screen buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
use(isAbsolute)
use(rect)
return checkError(r1, r2, err)
}
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
use(buffer)
use(bufferSize)
use(bufferCoord)
return checkError(r1, r2, err)
}
// ReadConsoleInput reads (and removes) data from the console input buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
use(buffer)
return checkError(r1, r2, err)
}
// WaitForSingleObject waits for the passed handle to be signaled.
// It returns true if the handle was signaled; false otherwise.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
switch r1 {
case WAIT_ABANDONED, WAIT_TIMEOUT:
return false, nil
case WAIT_SIGNALED:
return true, nil
}
use(msWait)
return false, err
}
// String helpers
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
}
func (coord COORD) String() string {
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
}
func (rect SMALL_RECT) String() string {
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
}
// checkError evaluates the results of a Windows API call and returns the error if it failed.
func checkError(r1, r2 uintptr, err error) error {
// Windows APIs return non-zero to indicate success
if r1 != 0 {
return nil
}
// Return the error if provided, otherwise default to EINVAL
if err != nil {
return err
}
return syscall.EINVAL
}
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
func coordToPointer(c COORD) uintptr {
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
}
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
func use(p interface{}) {}

View File

@@ -0,0 +1,100 @@
// +build windows
package winterm
import "github.com/Azure/go-ansiterm"
const (
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
)
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
// request represented by the passed ANSI mode.
func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
switch ansiMode {
// Mode styles
case ansiterm.ANSI_SGR_BOLD:
windowsMode = windowsMode | FOREGROUND_INTENSITY
case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
windowsMode &^= FOREGROUND_INTENSITY
case ansiterm.ANSI_SGR_UNDERLINE:
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
case ansiterm.ANSI_SGR_REVERSE:
inverted = true
case ansiterm.ANSI_SGR_REVERSE_OFF:
inverted = false
case ansiterm.ANSI_SGR_UNDERLINE_OFF:
windowsMode &^= COMMON_LVB_UNDERSCORE
// Foreground colors
case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
case ansiterm.ANSI_SGR_FOREGROUND_RED:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
// Background colors
case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
// Black with no intensity
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
case ansiterm.ANSI_SGR_BACKGROUND_RED:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
}
return windowsMode, inverted
}
// invertAttributes inverts the foreground and background colors of a Windows attributes value
func invertAttributes(windowsMode uint16) uint16 {
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
}

View File

@@ -0,0 +1,101 @@
// +build windows
package winterm
const (
horizontal = iota
vertical
)
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
if h.originMode {
sr := h.effectiveSr(info.Window)
return SMALL_RECT{
Top: sr.top,
Bottom: sr.bottom,
Left: 0,
Right: info.Size.X - 1,
}
} else {
return SMALL_RECT{
Top: info.Window.Top,
Bottom: info.Window.Bottom,
Left: 0,
Right: info.Size.X - 1,
}
}
}
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
position.X = ensureInRange(position.X, window.Left, window.Right)
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
err := SetConsoleCursorPosition(h.fd, position)
if err != nil {
return err
}
logger.Infof("Cursor position set: (%d, %d)", position.X, position.Y)
return err
}
func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
return h.moveCursor(vertical, param)
}
func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
return h.moveCursor(horizontal, param)
}
func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
switch moveMode {
case horizontal:
position.X += int16(param)
case vertical:
position.Y += int16(param)
}
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
position.X = 0
position.Y += int16(param)
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
position.X = int16(param) - 1
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}

Some files were not shown because too many files have changed in this diff Show More