Merge current v2.5 into master
This commit is contained in:
commit
89cd9e8ddd
102 changed files with 2402 additions and 1429 deletions
|
@ -48,6 +48,7 @@
|
|||
extensionsv1beta1 = "k8s.io/api/extensions/v1beta1"
|
||||
metav1 = "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeerror = "k8s.io/apimachinery/pkg/api/errors"
|
||||
composeapi = "github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
[linters-settings.gomoddirectives]
|
||||
replace-allow-list = [
|
||||
|
@ -56,6 +57,7 @@
|
|||
"github.com/gorilla/mux",
|
||||
"github.com/mailgun/minheap",
|
||||
"github.com/mailgun/multibuf",
|
||||
"github.com/jaguilar/vt100",
|
||||
]
|
||||
|
||||
[linters]
|
||||
|
|
|
@ -31,42 +31,24 @@ global_job_config:
|
|||
- cache restore traefik-$(checksum go.sum)
|
||||
|
||||
blocks:
|
||||
- name: Test Integration Container
|
||||
- name: Test Integration
|
||||
dependencies: []
|
||||
run:
|
||||
when: "branch =~ '.*' OR pull_request =~'.*'"
|
||||
task:
|
||||
jobs:
|
||||
- name: Test Integration Container
|
||||
- name: Test Integration
|
||||
commands:
|
||||
- make pull-images
|
||||
- mkdir -p webui/static && touch webui/static/index.html # Avoid generating webui
|
||||
- PRE_TARGET="" make binary
|
||||
- make test-integration-container
|
||||
- make test-integration
|
||||
- df -h
|
||||
epilogue:
|
||||
always:
|
||||
commands:
|
||||
- cache store traefik-$(checksum go.sum) $HOME/go/pkg/mod
|
||||
|
||||
- name: Test Integration Host
|
||||
dependencies: []
|
||||
run:
|
||||
when: "branch =~ '.*' OR pull_request =~'.*'"
|
||||
task:
|
||||
env_vars:
|
||||
- name: PRE_TARGET
|
||||
value: ""
|
||||
jobs:
|
||||
- name: Test Integration Host
|
||||
commands:
|
||||
- mkdir -p webui/static && touch webui/static/index.html # Avoid generating webui
|
||||
- make test-integration-host
|
||||
epilogue:
|
||||
always:
|
||||
commands:
|
||||
- cache store traefik-$(checksum go.sum) $HOME/go/pkg/mod
|
||||
|
||||
- name: Release
|
||||
dependencies: []
|
||||
run:
|
||||
|
|
34
Makefile
34
Makefile
|
@ -15,7 +15,7 @@ TRAEFIK_DEV_IMAGE := traefik-dev$(if $(GIT_BRANCH),:$(subst /,-,$(GIT_BRANCH)))
|
|||
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
||||
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"traefik/traefik")
|
||||
|
||||
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock")
|
||||
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)",)
|
||||
|
||||
TRAEFIK_ENVS := \
|
||||
|
@ -32,7 +32,8 @@ TRAEFIK_ENVS := \
|
|||
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/traefik/traefik/$(BIND_DIR)"
|
||||
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||
DOCKER_NON_INTERACTIVE ?= false
|
||||
DOCKER_RUN_TRAEFIK := docker run --add-host=host.docker.internal:127.0.0.1 $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK_TEST := docker run --add-host=host.docker.internal:127.0.0.1 --rm --name=traefik --network traefik-test-network -v $(PWD):$(PWD) -w $(PWD) $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -i) $(DOCKER_RUN_OPTS)
|
||||
|
||||
PRE_TARGET ?= build-dev-image
|
||||
|
@ -81,30 +82,27 @@ crossbinary-default-parallel:
|
|||
$(MAKE) build-dev-image crossbinary-default
|
||||
|
||||
## Run the unit and integration tests
|
||||
test: build-dev-image
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration
|
||||
test: $(PRE_TARGET)
|
||||
-docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
trap 'docker network rm traefik-test-network' EXIT; \
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK_TEST),) ./script/make.sh generate test-unit binary test-integration
|
||||
|
||||
## Run the unit tests
|
||||
test-unit: $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate test-unit
|
||||
-docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
trap 'docker network rm traefik-test-network' EXIT; \
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK_TEST)) ./script/make.sh generate test-unit
|
||||
|
||||
## Run the integration tests
|
||||
test-integration: $(PRE_TARGET)
|
||||
-docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
trap 'docker network rm traefik-test-network' EXIT; \
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK_TEST),) ./script/make.sh generate binary test-integration
|
||||
|
||||
## Pull all images for integration tests
|
||||
pull-images:
|
||||
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml | awk '{print $$2}' | sort | uniq | xargs -P 6 -n 1 docker pull
|
||||
|
||||
## Run the integration tests
|
||||
test-integration: $(PRE_TARGET) binary
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK),TEST_CONTAINER=1) ./script/make.sh test-integration
|
||||
TEST_HOST=1 ./script/make.sh test-integration
|
||||
|
||||
## Run the container integration tests
|
||||
test-integration-container: $(PRE_TARGET) binary
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK),TEST_CONTAINER=1) ./script/make.sh test-integration
|
||||
|
||||
## Run the host integration tests
|
||||
test-integration-host: $(PRE_TARGET) binary
|
||||
TEST_HOST=1 ./script/make.sh test-integration
|
||||
|
||||
## Validate code and docs
|
||||
validate-files: $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate validate-lint validate-misspell
|
||||
|
|
|
@ -349,12 +349,16 @@ http:
|
|||
|
||||
### `tls`
|
||||
|
||||
The `tls` option is the TLS configuration from Traefik to the authentication server.
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to the authentication server.
|
||||
|
||||
Certificate Authority used for the secured connection to the authentication server,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secured connection to the authentication server,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
|
@ -417,13 +421,15 @@ http:
|
|||
ca = "path/to/local.crt"
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to the authentication server.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to the authentication server.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -479,9 +485,12 @@ http:
|
|||
caOptional = true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
The public certificate used for the secure connection to the authentication server.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to the authentication server.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
|
@ -554,9 +563,12 @@ http:
|
|||
|
||||
For security reasons, the field does not exist for Kubernetes IngressRoute, and one should use the `secret` field instead.
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
The private certificate used for the secure connection to the authentication server.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to the authentication server.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
|
@ -629,7 +641,9 @@ http:
|
|||
|
||||
For security reasons, the field does not exist for Kubernetes IngressRoute, and one should use the `secret` field instead.
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to the authentication server accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -7,22 +7,6 @@ Traefik supports 4 metrics backends:
|
|||
- [Prometheus](./prometheus.md)
|
||||
- [StatsD](./statsd.md)
|
||||
|
||||
## Configuration
|
||||
|
||||
To enable metrics:
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--metrics=true
|
||||
```
|
||||
|
||||
## Server Metrics
|
||||
|
||||
| Metric | DataDog | InfluxDB | Prometheus | StatsD |
|
||||
|
|
|
@ -362,14 +362,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
Defines TLS options for Consul server endpoint.
|
||||
Defines the TLS configuration used for the secure connection to Consul Catalog.
|
||||
|
||||
##### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
Certificate Authority used for the secure connection to Consul,
|
||||
defaults to the system bundle.
|
||||
`ca` is the path to the certificate authority used for the secure connection to Consul Catalog,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -392,11 +392,11 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Consul.
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Consul Catalog.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -423,8 +423,7 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate to use for Consul communication.
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to Consul Catalog.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
|
@ -451,8 +450,7 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key for Consul communication.
|
||||
|
||||
`key` is the path to the private key used for the secure connection to Consul Catalog.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
|
@ -477,7 +475,7 @@ providers:
|
|||
|
||||
##### `insecureSkipVerify`
|
||||
|
||||
_Optional_
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to Consul accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -104,10 +104,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to Consul.
|
||||
|
||||
Certificate Authority used for the secure connection to Consul,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to Consul,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -125,13 +129,15 @@ providers:
|
|||
--providers.consul.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Consul.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Consul.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -153,9 +159,12 @@ providers:
|
|||
--providers.consul.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to Consul.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to Consul.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -176,9 +185,12 @@ providers:
|
|||
--providers.consul.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to Consul.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to Consul.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -199,7 +211,9 @@ providers:
|
|||
--providers.consul.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to Consul accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -613,10 +613,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to Docker.
|
||||
|
||||
Certificate Authority used for the secure connection to Docker,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to Docker,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -634,13 +638,15 @@ providers:
|
|||
--providers.docker.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Docker.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Docker.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -662,9 +668,10 @@ providers:
|
|||
--providers.docker.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to Docker.
|
||||
`cert` is the path to the public certificate used for the secure connection to Docker.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -685,9 +692,12 @@ providers:
|
|||
--providers.docker.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to Docker.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection Docker.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -708,7 +718,9 @@ providers:
|
|||
--providers.docker.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to Docker accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -104,10 +104,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to etcd.
|
||||
|
||||
Certificate Authority used for the secure connection to etcd,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to etcd,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -125,13 +129,15 @@ providers:
|
|||
--providers.etcd.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to etcd.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to etcd.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -153,9 +159,12 @@ providers:
|
|||
--providers.etcd.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to etcd.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to etcd.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -176,9 +185,12 @@ providers:
|
|||
--providers.etcd.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to etcd.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to etcd.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -199,7 +211,9 @@ providers:
|
|||
--providers.etcd.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to etcd accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ providers:
|
|||
|
||||
_Optional, Default="5s"_
|
||||
|
||||
Defines the polling timeout when connecting to the configured endpoint.
|
||||
Defines the polling timeout when connecting to the endpoint.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -76,10 +76,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to the endpoint.
|
||||
|
||||
Certificate Authority used for the secure connection to the configured endpoint,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to the endpoint,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -97,13 +101,15 @@ providers:
|
|||
--providers.http.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to the configured endpoint.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to the endpoint.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -125,9 +131,12 @@ providers:
|
|||
--providers.http.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to the configured endpoint.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to the endpoint.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -148,9 +157,12 @@ providers:
|
|||
--providers.http.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to the configured endpoint.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to the endpoint.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -171,7 +183,9 @@ providers:
|
|||
--providers.http.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to the endpoint accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -404,10 +404,12 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to Marathon.
|
||||
|
||||
Certificate Authority used for the secure connection to Marathon,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to Marathon,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -425,13 +427,15 @@ providers:
|
|||
--providers.marathon.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Marathon.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Marathon.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -453,9 +457,12 @@ providers:
|
|||
--providers.marathon.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to Marathon.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to Marathon.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -476,9 +483,12 @@ providers:
|
|||
--providers.marathon.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to Marathon.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to Marathon.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -499,7 +509,9 @@ providers:
|
|||
--providers.marathon.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to Marathon accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
@ -532,18 +544,18 @@ see [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration).
|
|||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
marathon:
|
||||
responseHeaderTimeout: "10s"
|
||||
tlsHandshakeTimeout: "10s"
|
||||
# ...
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.marathon]
|
||||
responseHeaderTimeout = "10s"
|
||||
tlsHandshakeTimeout = "10s"
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--providers.marathon.responseHeaderTimeout=10s
|
||||
--providers.marathon.tlsHandshakeTimeout=10s
|
||||
# ...
|
||||
```
|
||||
|
||||
|
|
|
@ -104,10 +104,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to Redis.
|
||||
|
||||
Certificate Authority used for the secure connection to Redis,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to Redis,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -125,13 +129,15 @@ providers:
|
|||
--providers.redis.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Redis.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Redis.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -153,9 +159,12 @@ providers:
|
|||
--providers.redis.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to Redis.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to Redis.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -176,9 +185,12 @@ providers:
|
|||
--providers.redis.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to Redis.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to Redis.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -199,7 +211,9 @@ providers:
|
|||
--providers.redis.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to Redis accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -104,10 +104,14 @@ providers:
|
|||
|
||||
_Optional_
|
||||
|
||||
#### `tls.ca`
|
||||
Defines the TLS configuration used for the secure connection to ZooKeeper.
|
||||
|
||||
Certificate Authority used for the secure connection to ZooKeeper,
|
||||
defaults to the system bundle.
|
||||
#### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to ZooKeeper,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -125,13 +129,15 @@ providers:
|
|||
--providers.zookeeper.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
#### `tls.caOptional`
|
||||
#### `caOptional`
|
||||
|
||||
The value of `tls.caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Zookeeper.
|
||||
_Optional_
|
||||
|
||||
The value of `caOptional` defines which policy should be used for the secure connection with TLS Client Authentication to Zookeeper.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
If `tls.ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
If `ca` is undefined, this option will be ignored, and no client certificate will be requested during the handshake. Any provided certificate will thus never be verified.
|
||||
|
||||
When this option is set to `true`, a client certificate is requested during the handshake but is not required. If a certificate is sent, it is required to be valid.
|
||||
|
||||
|
@ -153,9 +159,12 @@ providers:
|
|||
--providers.zookeeper.tls.caOptional=true
|
||||
```
|
||||
|
||||
#### `tls.cert`
|
||||
#### `cert`
|
||||
|
||||
Public certificate used for the secure connection to ZooKeeper.
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to ZooKeeper.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -176,9 +185,12 @@ providers:
|
|||
--providers.zookeeper.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.key`
|
||||
#### `key`
|
||||
|
||||
Private certificate used for the secure connection to ZooKeeper.
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to ZooKeeper.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
|
@ -199,7 +211,9 @@ providers:
|
|||
--providers.zookeeper.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
#### `tls.insecureSkipVerify`
|
||||
#### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to Zookeeper accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ For example, to change the rule, you could add the tag ```traefik.http.routers.m
|
|||
See [tls](../routers/index.md#tls) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter>.tls=true
|
||||
traefik.http.routers.myrouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
@ -136,7 +136,7 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
|
|||
See [serverstransport](../services/index.md#serverstransport) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file
|
||||
traefik.http.services.myservice.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
|
|
|
@ -251,7 +251,7 @@ The table below lists all the available matchers:
|
|||
|
||||
`HostRegexp` and `Path` accept an expression with zero or more groups enclosed by curly braces.
|
||||
Named groups can be like `{name:pattern}` that matches the given regexp pattern or like `{name}` that matches anything until the next dot.
|
||||
The group name (`name` is the above examples) is an arbitrary value.
|
||||
The group name (`name` in the above examples) is an arbitrary value.
|
||||
Any pattern supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used (example: `{subdomain:[a-z]+}.{domain}.com`).
|
||||
|
||||
!!! info "Combining Matchers Using Operators and Parenthesis"
|
||||
|
|
|
@ -336,11 +336,11 @@ Below are the available options for the health check mechanism:
|
|||
Traefik keeps monitoring the health of unhealthy servers.
|
||||
If a server has recovered (returning `2xx` -> `3xx` responses again), it will be added back to the load balancer rotation pool.
|
||||
|
||||
!!! warning "Health check in Kubernetes"
|
||||
!!! warning "Health check with Kubernetes"
|
||||
|
||||
The Traefik health check is not available for `kubernetesCRD` and `kubernetesIngress` providers because Kubernetes
|
||||
already has a health check mechanism.
|
||||
Unhealthy pods will be removed by kubernetes. (cf [liveness documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-http-request))
|
||||
Kubernetes has an health check mechanism to remove unhealthy pods from Kubernetes services (cf [readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes)).
|
||||
As unhealthy pods have no Kubernetes endpoints, Traefik will not forward traffic to them.
|
||||
Therefore, Traefik health check is not available for `kubernetesCRD` and `kubernetesIngress` providers.
|
||||
|
||||
??? example "Custom Interval & Timeout -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
|
|
36
go.mod
36
go.mod
|
@ -7,29 +7,25 @@ require (
|
|||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/Microsoft/hcsshim v0.8.7 // indirect
|
||||
github.com/Shopify/sarama v1.23.1 // indirect
|
||||
github.com/abbot/go-http-auth v0.0.0-00010101000000-000000000000
|
||||
github.com/abronan/valkeyrie v0.2.0
|
||||
github.com/aws/aws-sdk-go v1.39.0
|
||||
github.com/cenkalti/backoff/v4 v4.1.1
|
||||
github.com/containerd/containerd v1.3.2 // indirect
|
||||
github.com/compose-spec/compose-go v1.0.3
|
||||
github.com/containerd/containerd v1.5.8 // indirect
|
||||
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200204220554-5f6d6f3f2203+incompatible
|
||||
github.com/docker/docker-credential-helpers v0.6.3 // indirect
|
||||
github.com/docker/cli v20.10.11+incompatible
|
||||
github.com/docker/compose/v2 v2.0.1
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 // indirect
|
||||
github.com/docker/libcompose v0.0.0-20190805081528-eac9fe1b8b03 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
|
||||
github.com/eapache/channels v1.1.0
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
||||
github.com/go-acme/lego/v4 v4.5.0
|
||||
github.com/go-acme/lego/v4 v4.5.3
|
||||
github.com/go-check/check v0.0.0-00010101000000-000000000000
|
||||
github.com/go-kit/kit v0.10.1-0.20200915143503-439c4d2ed3ea
|
||||
github.com/golang/protobuf v1.5.2
|
||||
|
@ -40,24 +36,17 @@ require (
|
|||
github.com/hashicorp/consul/api v1.10.0
|
||||
github.com/hashicorp/go-hclog v0.16.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-version v1.2.1
|
||||
github.com/hashicorp/go-version v1.3.0
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d
|
||||
github.com/instana/go-sensor v1.31.1
|
||||
github.com/klauspost/compress v1.13.0
|
||||
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad
|
||||
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807
|
||||
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591
|
||||
github.com/lucas-clemente/quic-go v0.23.0
|
||||
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f
|
||||
github.com/miekg/dns v1.1.43
|
||||
github.com/mitchellh/copystructure v1.0.0
|
||||
github.com/mitchellh/hashstructure v1.0.0
|
||||
github.com/mitchellh/mapstructure v1.4.1
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v1.0.0-rc10 // indirect
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.4.2
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5
|
||||
github.com/openzipkin/zipkin-go v0.2.2
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
|
@ -67,12 +56,12 @@ require (
|
|||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
||||
github.com/tinylib/msgp v1.0.2 // indirect
|
||||
github.com/traefik/paerser v0.1.4
|
||||
github.com/traefik/yaegi v0.10.0
|
||||
github.com/traefik/yaegi v0.11.1
|
||||
github.com/uber/jaeger-client-go v2.29.1+incompatible
|
||||
github.com/uber/jaeger-lib v2.2.0+incompatible
|
||||
github.com/unrolled/render v1.0.2
|
||||
|
@ -108,3 +97,6 @@ replace (
|
|||
github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595
|
||||
github.com/mailgun/multibuf => github.com/containous/multibuf v0.0.0-20190809014333-8b6c9a7e6bba
|
||||
)
|
||||
|
||||
// https://github.com/docker/compose/blob/e44222664abd07ce1d1fe6796d84d93cbc7468c3/go.mod#L131
|
||||
replace github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305
|
||||
|
|
|
@ -36,12 +36,7 @@ type accessLogValue struct {
|
|||
|
||||
func (s *AccessLogSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "access_log")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeProject.Container(c, "server0")
|
||||
s.composeProject.Container(c, "server1")
|
||||
s.composeProject.Container(c, "server2")
|
||||
s.composeProject.Container(c, "server3")
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *AccessLogSuite) TearDownTest(c *check.C) {
|
||||
|
@ -122,7 +117,7 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
|||
code: "200",
|
||||
user: "test",
|
||||
routerName: "rt-authFrontend",
|
||||
serviceURL: "http://172.17.0",
|
||||
serviceURL: "http://172.31.42",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -136,8 +131,6 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
|||
|
||||
checkStatsForLogFile(c)
|
||||
|
||||
s.composeProject.Container(c, "authFrontend")
|
||||
|
||||
waitForTraefik(c, "authFrontend")
|
||||
|
||||
// Verify Traefik started OK
|
||||
|
@ -193,7 +186,7 @@ func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
|
|||
code: "200",
|
||||
user: "test",
|
||||
routerName: "rt-digestAuthMiddleware",
|
||||
serviceURL: "http://172.17.0",
|
||||
serviceURL: "http://172.31.42",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -207,8 +200,6 @@ func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
|
|||
|
||||
checkStatsForLogFile(c)
|
||||
|
||||
s.composeProject.Container(c, "digestAuthMiddleware")
|
||||
|
||||
waitForTraefik(c, "digestAuthMiddleware")
|
||||
|
||||
// Verify Traefik started OK
|
||||
|
@ -322,8 +313,6 @@ func (s *AccessLogSuite) TestAccessLogFrontendRedirect(c *check.C) {
|
|||
|
||||
checkStatsForLogFile(c)
|
||||
|
||||
s.composeProject.Container(c, "frontendRedirect")
|
||||
|
||||
waitForTraefik(c, "frontendRedirect")
|
||||
|
||||
// Verify Traefik started OK
|
||||
|
@ -375,8 +364,6 @@ func (s *AccessLogSuite) TestAccessLogRateLimit(c *check.C) {
|
|||
|
||||
checkStatsForLogFile(c)
|
||||
|
||||
s.composeProject.Container(c, "rateLimit")
|
||||
|
||||
waitForTraefik(c, "rateLimit")
|
||||
|
||||
// Verify Traefik started OK
|
||||
|
@ -471,8 +458,6 @@ func (s *AccessLogSuite) TestAccessLogFrontendWhitelist(c *check.C) {
|
|||
|
||||
checkStatsForLogFile(c)
|
||||
|
||||
s.composeProject.Container(c, "frontendWhitelist")
|
||||
|
||||
waitForTraefik(c, "frontendWhitelist")
|
||||
|
||||
// Verify Traefik started OK
|
||||
|
@ -504,7 +489,7 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess(c *check.C) {
|
|||
code: "200",
|
||||
user: "test",
|
||||
routerName: "rt-authFrontend",
|
||||
serviceURL: "http://172.17.0",
|
||||
serviceURL: "http://172.31.42",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -518,8 +503,6 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess(c *check.C) {
|
|||
|
||||
checkStatsForLogFile(c)
|
||||
|
||||
s.composeProject.Container(c, "authFrontend")
|
||||
|
||||
waitForTraefik(c, "authFrontend")
|
||||
|
||||
// Verify Traefik started OK
|
||||
|
@ -548,7 +531,6 @@ func checkNoOtherTraefikProblems(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
if len(traefikLog) > 0 {
|
||||
fmt.Printf("%s\n", string(traefikLog))
|
||||
c.Assert(traefikLog, checker.HasLen, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -616,7 +598,6 @@ func checkTraefikStarted(c *check.C) []byte {
|
|||
c.Assert(err, checker.IsNil)
|
||||
if len(traefikLog) > 0 {
|
||||
fmt.Printf("%s\n", string(traefikLog))
|
||||
c.Assert(traefikLog, checker.HasLen, 0)
|
||||
}
|
||||
return traefikLog
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -19,7 +20,7 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// ACME test suites (using libcompose).
|
||||
// ACME test suites.
|
||||
type AcmeSuite struct {
|
||||
BaseSuite
|
||||
pebbleIP string
|
||||
|
@ -54,7 +55,8 @@ const (
|
|||
)
|
||||
|
||||
func (s *AcmeSuite) getAcmeURL() string {
|
||||
return fmt.Sprintf("https://%s:14000/dir", s.pebbleIP)
|
||||
return fmt.Sprintf("https://%s/dir",
|
||||
net.JoinHostPort(s.pebbleIP, "14000"))
|
||||
}
|
||||
|
||||
func setupPebbleRootCA() (*http.Transport, error) {
|
||||
|
@ -86,11 +88,10 @@ func setupPebbleRootCA() (*http.Transport, error) {
|
|||
|
||||
func (s *AcmeSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "pebble")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.fakeDNSServer = startFakeDNSServer()
|
||||
|
||||
s.pebbleIP = s.composeProject.Container(c, "pebble").NetworkSettings.IPAddress
|
||||
s.fakeDNSServer = startFakeDNSServer(s.getContainerIP(c, "traefik"))
|
||||
s.pebbleIP = s.getComposeServiceIP(c, "pebble")
|
||||
|
||||
pebbleTransport, err := setupPebbleRootCA()
|
||||
if err != nil {
|
||||
|
@ -115,15 +116,14 @@ func (s *AcmeSuite) SetUpSuite(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *AcmeSuite) TearDownSuite(c *check.C) {
|
||||
err := s.fakeDNSServer.Shutdown()
|
||||
if err != nil {
|
||||
c.Log(err)
|
||||
if s.fakeDNSServer != nil {
|
||||
err := s.fakeDNSServer.Shutdown()
|
||||
if err != nil {
|
||||
c.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
s.composeDown(c)
|
||||
}
|
||||
|
||||
func (s *AcmeSuite) TestHTTP01Domains(c *check.C) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package integration
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -14,32 +15,31 @@ import (
|
|||
|
||||
type ConsulCatalogSuite struct {
|
||||
BaseSuite
|
||||
consulClient *api.Client
|
||||
consulAgentClient *api.Client
|
||||
consulAddress string
|
||||
consulAgentAddress string
|
||||
consulClient *api.Client
|
||||
consulAgentClient *api.Client
|
||||
consulURL string
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "consul_catalog")
|
||||
s.composeProject.Start(c)
|
||||
s.consulAddress = "http://" + s.composeProject.Container(c, "consul").NetworkSettings.IPAddress + ":8500"
|
||||
client, err := api.NewClient(&api.Config{
|
||||
Address: s.consulAddress,
|
||||
s.composeUp(c)
|
||||
|
||||
s.consulURL = "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "consul"), "8500")
|
||||
|
||||
var err error
|
||||
s.consulClient, err = api.NewClient(&api.Config{
|
||||
Address: s.consulURL,
|
||||
})
|
||||
c.Check(err, check.IsNil)
|
||||
s.consulClient = client
|
||||
|
||||
// Wait for consul to elect itself leader
|
||||
err = s.waitToElectConsulLeader()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
s.consulAgentAddress = "http://" + s.composeProject.Container(c, "consul-agent").NetworkSettings.IPAddress + ":8500"
|
||||
clientAgent, err := api.NewClient(&api.Config{
|
||||
Address: s.consulAgentAddress,
|
||||
s.consulAgentClient, err = api.NewClient(&api.Config{
|
||||
Address: "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "consul-agent"), "8500"),
|
||||
})
|
||||
c.Check(err, check.IsNil)
|
||||
s.consulAgentClient = clientAgent
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
||||
|
@ -66,13 +66,6 @@ func (s *ConsulCatalogSuite) waitForConnectCA() error {
|
|||
})
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) TearDownSuite(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) registerService(reg *api.AgentServiceRegistration, onAgent bool) error {
|
||||
client := s.consulClient
|
||||
if onAgent {
|
||||
|
@ -96,7 +89,7 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
|
|||
Name: "whoami",
|
||||
Tags: []string{"traefik.enable=true"},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami1"),
|
||||
}
|
||||
err := s.registerService(reg1, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -106,7 +99,7 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
|
|||
Name: "whoami",
|
||||
Tags: []string{"traefik.enable=true"},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami2"),
|
||||
}
|
||||
err = s.registerService(reg2, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -116,7 +109,7 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
|
|||
Name: "whoami",
|
||||
Tags: []string{"traefik.enable=true"},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami3"),
|
||||
}
|
||||
err = s.registerService(reg3, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -124,7 +117,7 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
|
|||
tempObjects := struct {
|
||||
ConsulAddress string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
}
|
||||
|
||||
file := s.adaptFile(c, "fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
|
||||
|
@ -163,7 +156,7 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
|
|||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) TestByLabels(c *check.C) {
|
||||
containerIP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
containerIP := s.getComposeServiceIP(c, "whoami1")
|
||||
|
||||
reg := &api.AgentServiceRegistration{
|
||||
ID: "whoami1",
|
||||
|
@ -183,7 +176,7 @@ func (s *ConsulCatalogSuite) TestByLabels(c *check.C) {
|
|||
tempObjects := struct {
|
||||
ConsulAddress string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
}
|
||||
|
||||
file := s.adaptFile(c, "fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
|
||||
|
@ -195,7 +188,7 @@ func (s *ConsulCatalogSuite) TestByLabels(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContainsOr("Hostname: whoami1", "Hostname: whoami2", "Hostname: whoami3"))
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContainsOr("Hostname: whoami1", "Hostname: whoami2", "Hostname: whoami3"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.deregisterService("whoami1", false)
|
||||
|
@ -207,7 +200,7 @@ func (s *ConsulCatalogSuite) TestSimpleConfiguration(c *check.C) {
|
|||
ConsulAddress string
|
||||
DefaultRule string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -219,7 +212,7 @@ func (s *ConsulCatalogSuite) TestSimpleConfiguration(c *check.C) {
|
|||
Name: "whoami",
|
||||
Tags: []string{"traefik.enable=true"},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami1"),
|
||||
}
|
||||
err := s.registerService(reg, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -246,7 +239,7 @@ func (s *ConsulCatalogSuite) TestRegisterServiceWithoutIP(c *check.C) {
|
|||
ConsulAddress string
|
||||
DefaultRule string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -285,7 +278,7 @@ func (s *ConsulCatalogSuite) TestDefaultConsulService(c *check.C) {
|
|||
DefaultRule string
|
||||
}{
|
||||
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -296,7 +289,7 @@ func (s *ConsulCatalogSuite) TestDefaultConsulService(c *check.C) {
|
|||
ID: "whoami1",
|
||||
Name: "whoami",
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami1"),
|
||||
}
|
||||
err := s.registerService(reg, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -324,7 +317,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithTCPLabels(c *check.C) {
|
|||
ConsulAddress string
|
||||
DefaultRule string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -341,7 +334,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithTCPLabels(c *check.C) {
|
|||
"traefik.tcp.Services.Super.Loadbalancer.server.port=8080",
|
||||
},
|
||||
Port: 8080,
|
||||
Address: s.composeProject.Container(c, "whoamitcp").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoamitcp"),
|
||||
}
|
||||
|
||||
err := s.registerService(reg, false)
|
||||
|
@ -371,7 +364,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
|
|||
ConsulAddress string
|
||||
DefaultRule string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -386,7 +379,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
|
|||
"traefik.http.Routers.Super.Rule=Host(`my.super.host`)",
|
||||
},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami1"),
|
||||
}
|
||||
|
||||
err := s.registerService(reg1, false)
|
||||
|
@ -400,7 +393,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
|
|||
"traefik.http.Routers.SuperHost.Rule=Host(`my-super.host`)",
|
||||
},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami2"),
|
||||
}
|
||||
err = s.registerService(reg2, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -438,7 +431,7 @@ func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C)
|
|||
ConsulAddress string
|
||||
DefaultRule string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -457,7 +450,7 @@ func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C)
|
|||
Name: "whoami",
|
||||
Tags: tags,
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami1"),
|
||||
}
|
||||
err := s.registerService(reg1, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -467,7 +460,7 @@ func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C)
|
|||
Name: "whoami",
|
||||
Tags: tags,
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami2"),
|
||||
}
|
||||
err = s.registerService(reg2, true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -490,8 +483,7 @@ func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C)
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200),
|
||||
try.BodyContainsOr(s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress))
|
||||
try.BodyContainsOr(s.getComposeServiceIP(c, "whoami1"), s.getComposeServiceIP(c, "whoami2")))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.deregisterService("whoami", false)
|
||||
|
@ -506,7 +498,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
|
|||
ConsulAddress string
|
||||
DefaultRule string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
|
||||
}
|
||||
|
||||
|
@ -521,7 +513,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
|
|||
"traefik.random.value=my.super.host",
|
||||
},
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: s.getComposeServiceIP(c, "whoami1"),
|
||||
}
|
||||
|
||||
err := s.registerService(reg, false)
|
||||
|
@ -546,11 +538,12 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
|
||||
whoamiIP := s.getComposeServiceIP(c, "whoami1")
|
||||
tags := []string{
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.router1.rule=Path(`/whoami`)",
|
||||
"traefik.http.routers.router1.service=service1",
|
||||
"traefik.http.services.service1.loadBalancer.server.url=http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
"traefik.http.services.service1.loadBalancer.server.url=http://" + whoamiIP,
|
||||
}
|
||||
|
||||
reg1 := &api.AgentServiceRegistration{
|
||||
|
@ -558,7 +551,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
|
|||
Name: "whoami",
|
||||
Tags: tags,
|
||||
Port: 80,
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress,
|
||||
Address: whoamiIP,
|
||||
Check: &api.AgentServiceCheck{
|
||||
CheckID: "some-failed-check",
|
||||
TCP: "127.0.0.1:1234",
|
||||
|
@ -574,7 +567,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
|
|||
tempObjects := struct {
|
||||
ConsulAddress string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
}
|
||||
|
||||
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
|
||||
|
@ -592,17 +585,16 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
|
|||
err = s.deregisterService("whoami1", false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
containerIP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
|
||||
whoami2IP := s.getComposeServiceIP(c, "whoami2")
|
||||
reg2 := &api.AgentServiceRegistration{
|
||||
ID: "whoami2",
|
||||
Name: "whoami",
|
||||
Tags: tags,
|
||||
Port: 80,
|
||||
Address: containerIP,
|
||||
Address: whoami2IP,
|
||||
Check: &api.AgentServiceCheck{
|
||||
CheckID: "some-ok-check",
|
||||
TCP: containerIP + ":80",
|
||||
TCP: whoami2IP + ":80",
|
||||
Name: "some-ok-check",
|
||||
Interval: "1s",
|
||||
Timeout: "1s",
|
||||
|
@ -629,7 +621,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect(c *check.C) {
|
|||
err := s.waitForConnectCA()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
connectIP := s.composeProject.Container(c, "connect").NetworkSettings.IPAddress
|
||||
connectIP := s.getComposeServiceIP(c, "connect")
|
||||
reg := &api.AgentServiceRegistration{
|
||||
ID: "uuid-api1",
|
||||
Name: "uuid-api",
|
||||
|
@ -649,7 +641,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect(c *check.C) {
|
|||
err = s.registerService(reg, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
whoamiIP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
whoamiIP := s.getComposeServiceIP(c, "whoami1")
|
||||
regWhoami := &api.AgentServiceRegistration{
|
||||
ID: "whoami1",
|
||||
Name: "whoami",
|
||||
|
@ -667,7 +659,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect(c *check.C) {
|
|||
tempObjects := struct {
|
||||
ConsulAddress string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
}
|
||||
file := s.adaptFile(c, "fixtures/consul_catalog/connect.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
@ -695,7 +687,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
|
|||
err := s.waitForConnectCA()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
connectIP := s.composeProject.Container(c, "connect").NetworkSettings.IPAddress
|
||||
connectIP := s.getComposeServiceIP(c, "connect")
|
||||
reg := &api.AgentServiceRegistration{
|
||||
ID: "uuid-api1",
|
||||
Name: "uuid-api",
|
||||
|
@ -714,7 +706,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
|
|||
err = s.registerService(reg, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
whoamiIP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
whoamiIP := s.getComposeServiceIP(c, "whoami1")
|
||||
regWhoami := &api.AgentServiceRegistration{
|
||||
ID: "whoami1",
|
||||
Name: "whoami1",
|
||||
|
@ -729,7 +721,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
|
|||
err = s.registerService(regWhoami, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
whoami2IP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
whoami2IP := s.getComposeServiceIP(c, "whoami2")
|
||||
regWhoami2 := &api.AgentServiceRegistration{
|
||||
ID: "whoami2",
|
||||
Name: "whoami2",
|
||||
|
@ -748,7 +740,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
|
|||
tempObjects := struct {
|
||||
ConsulAddress string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
}
|
||||
file := s.adaptFile(c, "fixtures/consul_catalog/connect_by_default.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
@ -781,7 +773,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware(c *check.C) {
|
|||
err := s.waitForConnectCA()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
connectIP := s.composeProject.Container(c, "connect").NetworkSettings.IPAddress
|
||||
connectIP := s.getComposeServiceIP(c, "connect")
|
||||
reg := &api.AgentServiceRegistration{
|
||||
ID: "uuid-api1",
|
||||
Name: "uuid-api",
|
||||
|
@ -801,7 +793,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware(c *check.C) {
|
|||
err = s.registerService(reg, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
whoamiIP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
whoamiIP := s.getComposeServiceIP(c, "whoami1")
|
||||
regWhoami := &api.AgentServiceRegistration{
|
||||
ID: "whoami1",
|
||||
Name: "whoami",
|
||||
|
@ -819,7 +811,7 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware(c *check.C) {
|
|||
tempObjects := struct {
|
||||
ConsulAddress string
|
||||
}{
|
||||
ConsulAddress: s.consulAddress,
|
||||
ConsulAddress: s.consulURL,
|
||||
}
|
||||
file := s.adaptFile(c, "fixtures/consul_catalog/connect_not_aware.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
|
|
@ -3,6 +3,8 @@ package integration
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -18,20 +20,24 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Consul test suites (using libcompose).
|
||||
// Consul test suites.
|
||||
type ConsulSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
kvClient store.Store
|
||||
consulURL string
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) setupStore(c *check.C) {
|
||||
s.createComposeProject(c, "consul")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
consulAddr := net.JoinHostPort(s.getComposeServiceIP(c, "consul"), "8500")
|
||||
s.consulURL = fmt.Sprintf("http://%s", consulAddr)
|
||||
|
||||
consul.Register()
|
||||
kv, err := valkeyrie.NewStore(
|
||||
store.CONSUL,
|
||||
[]string{s.composeProject.Container(c, "consul").NetworkSettings.IPAddress + ":8500"},
|
||||
[]string{consulAddr},
|
||||
&store.Config{
|
||||
ConnectionTimeout: 10 * time.Second,
|
||||
},
|
||||
|
@ -46,20 +52,10 @@ func (s *ConsulSuite) setupStore(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) TearDownTest(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) TearDownSuite(c *check.C) {}
|
||||
|
||||
func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
|
||||
s.setupStore(c)
|
||||
|
||||
address := "http://" + s.composeProject.Container(c, "consul").NetworkSettings.IPAddress + ":8500"
|
||||
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulAddress string }{address})
|
||||
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
|
||||
defer os.Remove(file)
|
||||
|
||||
data := map[string]string{
|
||||
|
|
|
@ -14,33 +14,17 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
const (
|
||||
composeProject = "minimal"
|
||||
)
|
||||
|
||||
// Docker tests suite.
|
||||
type DockerComposeSuite struct {
|
||||
BaseSuite
|
||||
}
|
||||
|
||||
func (s *DockerComposeSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, composeProject)
|
||||
s.composeProject.Start(c)
|
||||
}
|
||||
|
||||
func (s *DockerComposeSuite) TearDownSuite(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
s.createComposeProject(c, "minimal")
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *DockerComposeSuite) TestComposeScale(c *check.C) {
|
||||
serviceCount := 2
|
||||
composeService := "whoami1"
|
||||
|
||||
s.composeProject.Scale(c, composeService, serviceCount)
|
||||
|
||||
tempObjects := struct {
|
||||
DockerHost string
|
||||
DefaultRule string
|
||||
|
@ -81,8 +65,8 @@ func (s *DockerComposeSuite) TestComposeScale(c *check.C) {
|
|||
if strings.HasSuffix(name, "@internal") {
|
||||
continue
|
||||
}
|
||||
c.Assert(name, checker.Equals, composeService+"-integrationtest"+composeProject+"@docker")
|
||||
c.Assert(service.LoadBalancer.Servers, checker.HasLen, serviceCount)
|
||||
c.Assert(name, checker.Equals, "whoami1-"+s.composeProject.Name+"@docker")
|
||||
c.Assert(service.LoadBalancer.Servers, checker.HasLen, 2)
|
||||
// We could break here, but we don't just to keep us honest.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,80 +6,24 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/namesgenerator"
|
||||
"github.com/go-check/check"
|
||||
d "github.com/libkermit/docker"
|
||||
"github.com/libkermit/docker-check"
|
||||
"github.com/traefik/traefik/v2/integration/try"
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Images to have or pull before the build in order to make it work.
|
||||
// FIXME handle this offline but loading them before build.
|
||||
var RequiredImages = map[string]string{
|
||||
"swarm": "1.0.0",
|
||||
"traefik/whoami": "latest",
|
||||
}
|
||||
|
||||
// Docker tests suite.
|
||||
type DockerSuite struct {
|
||||
BaseSuite
|
||||
project *docker.Project
|
||||
}
|
||||
|
||||
func (s *DockerSuite) startContainer(c *check.C, image string, args ...string) string {
|
||||
return s.startContainerWithConfig(c, image, d.ContainerConfig{
|
||||
Cmd: args,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) startContainerWithLabels(c *check.C, image string, labels map[string]string, args ...string) string {
|
||||
return s.startContainerWithConfig(c, image, d.ContainerConfig{
|
||||
Cmd: args,
|
||||
Labels: labels,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) startContainerWithNameAndLabels(c *check.C, name, image string, labels map[string]string, args ...string) string {
|
||||
return s.startContainerWithConfig(c, image, d.ContainerConfig{
|
||||
Name: name,
|
||||
Cmd: args,
|
||||
Labels: labels,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) startContainerWithConfig(c *check.C, image string, config d.ContainerConfig) string {
|
||||
if config.Name == "" {
|
||||
config.Name = namesgenerator.GetRandomName(10)
|
||||
}
|
||||
|
||||
container := s.project.StartWithConfig(c, image, config)
|
||||
|
||||
// FIXME(vdemeester) this is ugly (it's because of the / in front of the name in docker..)
|
||||
return strings.SplitAfter(container.Name, "/")[1]
|
||||
}
|
||||
|
||||
func (s *DockerSuite) stopAndRemoveContainerByName(c *check.C, name string) {
|
||||
s.project.Stop(c, name)
|
||||
s.project.Remove(c, name)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) SetUpSuite(c *check.C) {
|
||||
project := docker.NewProjectFromEnv(c)
|
||||
s.project = project
|
||||
|
||||
// Pull required images
|
||||
for repository, tag := range RequiredImages {
|
||||
image := fmt.Sprintf("%s:%s", repository, tag)
|
||||
s.project.Pull(c, image)
|
||||
}
|
||||
func (s *DockerSuite) SetUpTest(c *check.C) {
|
||||
s.createComposeProject(c, "docker")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TearDownTest(c *check.C) {
|
||||
s.project.Clean(c, os.Getenv("CIRCLECI") != "") // FIXME
|
||||
s.composeDown(c)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
@ -94,13 +38,15 @@ func (s *DockerSuite) TestSimpleConfiguration(c *check.C) {
|
|||
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
||||
s.composeUp(c)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
// TODO validate : run on 80
|
||||
// Expected a 404 as we did not configure anything
|
||||
err = try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -118,18 +64,19 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
|
|||
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
||||
name := s.startContainer(c, "swarm:1.0.0", "manage", "token://blablabla")
|
||||
s.composeUp(c, "simple")
|
||||
|
||||
// Start traefik
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = fmt.Sprintf("%s.docker.localhost", strings.ReplaceAll(name, "_", "-"))
|
||||
req.Host = fmt.Sprintf("simple-%s.docker.localhost", s.composeProject.Name)
|
||||
|
||||
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
|
||||
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
|
||||
|
@ -156,18 +103,12 @@ func (s *DockerSuite) TestDockerContainersWithTCPLabels(c *check.C) {
|
|||
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
||||
// Start a container with some labels
|
||||
labels := map[string]string{
|
||||
"traefik.tcp.Routers.Super.Rule": "HostSNI(`my.super.host`)",
|
||||
"traefik.tcp.Routers.Super.tls": "true",
|
||||
"traefik.tcp.Services.Super.Loadbalancer.server.port": "8080",
|
||||
}
|
||||
|
||||
s.startContainerWithLabels(c, "traefik/whoamitcp", labels, "-name", "my.super.host")
|
||||
s.composeUp(c, "withtcplabels")
|
||||
|
||||
// Start traefik
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
@ -193,17 +134,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
|
|||
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
||||
// Start a container with some labels
|
||||
labels := map[string]string{
|
||||
"traefik.http.Routers.Super.Rule": "Host(`my.super.host`)",
|
||||
}
|
||||
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||
|
||||
// Start another container by replacing a '.' by a '-'
|
||||
labels = map[string]string{
|
||||
"traefik.http.Routers.SuperHost.Rule": "Host(`my-super.host`)",
|
||||
}
|
||||
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blablabla")
|
||||
s.composeUp(c, "withlabels1", "withlabels2")
|
||||
|
||||
// Start traefik
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -249,15 +180,12 @@ func (s *DockerSuite) TestDockerContainersWithOneMissingLabels(c *check.C) {
|
|||
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
||||
// Start a container with some labels
|
||||
labels := map[string]string{
|
||||
"traefik.random.value": "my.super.host",
|
||||
}
|
||||
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||
s.composeUp(c, "withonelabelmissing")
|
||||
|
||||
// Start traefik
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
@ -285,16 +213,12 @@ func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
|
|||
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||
defer os.Remove(file)
|
||||
|
||||
// Start a container with some labels
|
||||
labels := map[string]string{
|
||||
"traefik.http.Routers.Super.Rule": "Host(`my.super.host`)",
|
||||
"traefik.http.Services.powpow.LoadBalancer.server.Port": "2375",
|
||||
}
|
||||
s.startContainerWithNameAndLabels(c, "powpow", "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||
s.composeUp(c, "powpow")
|
||||
|
||||
// Start traefik
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
@ -318,16 +242,14 @@ func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("powpow"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
s.stopAndRemoveContainerByName(c, "powpow")
|
||||
defer s.project.Remove(c, "powpow")
|
||||
s.composeStop(c, "powpow")
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("powpow"))
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
s.startContainerWithNameAndLabels(c, "powpow", "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||
|
||||
s.composeUp(c, "powpow")
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("powpow"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// ErrorPagesSuite test suites (using libcompose).
|
||||
// ErrorPagesSuite test suites.
|
||||
type ErrorPagesSuite struct {
|
||||
BaseSuite
|
||||
ErrorPageIP string
|
||||
|
@ -19,10 +19,10 @@ type ErrorPagesSuite struct {
|
|||
|
||||
func (s *ErrorPagesSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "error_pages")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.ErrorPageIP = s.composeProject.Container(c, "nginx2").NetworkSettings.IPAddress
|
||||
s.BackendIP = s.composeProject.Container(c, "nginx1").NetworkSettings.IPAddress
|
||||
s.ErrorPageIP = s.getComposeServiceIP(c, "nginx2")
|
||||
s.BackendIP = s.getComposeServiceIP(c, "nginx1")
|
||||
}
|
||||
|
||||
func (s *ErrorPagesSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package integration
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -18,20 +19,24 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// etcd test suites (using libcompose).
|
||||
// etcd test suites.
|
||||
type EtcdSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
etcdAddr string
|
||||
}
|
||||
|
||||
func (s *EtcdSuite) setupStore(c *check.C) {
|
||||
func (s *EtcdSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "etcd")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
etcdv3.Register()
|
||||
kv, err := valkeyrie.NewStore(
|
||||
|
||||
var err error
|
||||
s.etcdAddr = net.JoinHostPort(s.getComposeServiceIP(c, "etcd"), "2379")
|
||||
s.kvClient, err = valkeyrie.NewStore(
|
||||
store.ETCDV3,
|
||||
[]string{s.composeProject.Container(c, "etcd").NetworkSettings.IPAddress + ":2379"},
|
||||
[]string{s.etcdAddr},
|
||||
&store.Config{
|
||||
ConnectionTimeout: 10 * time.Second,
|
||||
},
|
||||
|
@ -39,27 +44,14 @@ func (s *EtcdSuite) setupStore(c *check.C) {
|
|||
if err != nil {
|
||||
c.Fatal("Cannot create store etcd")
|
||||
}
|
||||
s.kvClient = kv
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
|
||||
err = try.Do(60*time.Second, try.KVExists(s.kvClient, "test"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *EtcdSuite) TearDownTest(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EtcdSuite) TearDownSuite(c *check.C) {}
|
||||
|
||||
func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
|
||||
s.setupStore(c)
|
||||
|
||||
address := s.composeProject.Container(c, "etcd").NetworkSettings.IPAddress + ":2379"
|
||||
file := s.adaptFile(c, "fixtures/etcd/simple.toml", struct{ EtcdAddress string }{address})
|
||||
file := s.adaptFile(c, "fixtures/etcd/simple.toml", struct{ EtcdAddress string }{s.etcdAddr})
|
||||
defer os.Remove(file)
|
||||
|
||||
data := map[string]string{
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
)
|
||||
|
||||
type handler struct{}
|
||||
type handler struct {
|
||||
traefikIP string
|
||||
}
|
||||
|
||||
// ServeDNS a fake DNS server
|
||||
// Simplified version of the Challenge Test Server from Boulder
|
||||
|
@ -21,11 +23,6 @@ func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
m.SetReply(r)
|
||||
m.Compress = false
|
||||
|
||||
fakeDNS := os.Getenv("DOCKER_HOST_IP")
|
||||
if fakeDNS == "" {
|
||||
fakeDNS = "127.0.0.1"
|
||||
}
|
||||
|
||||
for _, q := range r.Question {
|
||||
logger.Infof("Query -- [%s] %s", q.Name, dns.TypeToString[q.Qtype])
|
||||
|
||||
|
@ -38,7 +35,7 @@ func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
Class: dns.ClassINET,
|
||||
Ttl: 0,
|
||||
}
|
||||
record.A = net.ParseIP(fakeDNS)
|
||||
record.A = net.ParseIP(s.traefikIP)
|
||||
|
||||
m.Answer = append(m.Answer, record)
|
||||
case dns.TypeCAA:
|
||||
|
@ -101,11 +98,11 @@ func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
}
|
||||
}
|
||||
|
||||
func startFakeDNSServer() *dns.Server {
|
||||
func startFakeDNSServer(traefikIP string) *dns.Server {
|
||||
srv := &dns.Server{
|
||||
Addr: ":5053",
|
||||
Net: "udp",
|
||||
Handler: &handler{},
|
||||
Handler: &handler{traefikIP},
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
|
|
@ -15,7 +15,7 @@ type FileSuite struct{ BaseSuite }
|
|||
|
||||
func (s *FileSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "file")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
[http.services]
|
||||
[http.services.service2.loadBalancer]
|
||||
[[http.services.service2.loadBalancer.servers]]
|
||||
url = "http://172.17.0.123:80"
|
||||
url = "http://127.0.0.1:80"
|
||||
|
|
|
@ -33,13 +33,13 @@
|
|||
[http.services.service1.loadBalancer]
|
||||
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiEndpoint}}:8080"
|
||||
url = "http://{{ .WhoamiIP }}:8080"
|
||||
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiEndpoint}}:8081"
|
||||
url = "http://{{ .WhoamiIP }}:8081"
|
||||
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiEndpoint}}:8082"
|
||||
url = "http://{{ .WhoamiIP }}:8082"
|
||||
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiEndpoint}}:80"
|
||||
url = "http://{{ .WhoamiIP }}:80"
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
[http.services.service1.loadBalancer]
|
||||
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiEndpoint}}:8080"
|
||||
url = "http://{{ .WhoamiIP }}:8080"
|
||||
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiEndpoint}}:80"
|
||||
url = "http://{{ .WhoamiIP }}:80"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
[tcp.services]
|
||||
[tcp.services.whoami-no-tls.loadBalancer]
|
||||
[[tcp.services.whoami-no-tls.loadBalancer.servers]]
|
||||
address = "localhost:8086"
|
||||
address = "whoami-no-tls:8080"
|
||||
|
||||
[http]
|
||||
[http.routers]
|
||||
|
@ -40,4 +40,4 @@
|
|||
[http.services]
|
||||
[http.services.whoami.loadBalancer]
|
||||
[[http.services.whoami.loadBalancer.servers]]
|
||||
url = "http://localhost:8085"
|
||||
url = "http://whoami:80"
|
||||
|
|
|
@ -27,4 +27,4 @@
|
|||
[tcp.services]
|
||||
[tcp.services.whoami-no-tls.loadBalancer]
|
||||
[[tcp.services.whoami-no-tls.loadBalancer.servers]]
|
||||
address = "localhost:8086"
|
||||
address = "whoami-banner:8080"
|
||||
|
|
|
@ -38,18 +38,14 @@
|
|||
[tcp.services]
|
||||
[tcp.services.whoami-a.loadBalancer]
|
||||
[[tcp.services.whoami-a.loadBalancer.servers]]
|
||||
address = "localhost:8081"
|
||||
address = "whoami-a:8080"
|
||||
|
||||
[tcp.services.whoami-b.loadBalancer]
|
||||
[[tcp.services.whoami-b.loadBalancer.servers]]
|
||||
address = "localhost:8082"
|
||||
address = "whoami-b:8080"
|
||||
|
||||
[tcp.middlewares]
|
||||
[tcp.middlewares.allowing-ipwhitelist.ipWhiteList]
|
||||
sourceRange = ["127.0.0.1/32"]
|
||||
[tcp.middlewares.blocking-ipwhitelist.ipWhiteList]
|
||||
sourceRange = ["127.127.127.127/32"]
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "fixtures/tcp/whoami-c.crt"
|
||||
keyFile = "fixtures/tcp/whoami-c.key"
|
||||
|
|
|
@ -29,11 +29,15 @@
|
|||
rule = "Path(`/whoami/`)"
|
||||
service = "whoami"
|
||||
[http.routers.my-https-router.tls]
|
||||
[http.routers.api]
|
||||
rule = "PathPrefix(`/api`)"
|
||||
service = "api@internal"
|
||||
entryPoints = ["traefik"]
|
||||
|
||||
[http.services]
|
||||
[http.services.whoami.loadBalancer]
|
||||
[[http.services.whoami.loadBalancer.servers]]
|
||||
url = "http://localhost:8085"
|
||||
url = "http://whoami:80"
|
||||
[tcp]
|
||||
[tcp.routers]
|
||||
[tcp.routers.to-whoami-a]
|
||||
|
@ -58,15 +62,15 @@
|
|||
|
||||
[tcp.services.whoami-a.loadBalancer]
|
||||
[[tcp.services.whoami-a.loadBalancer.servers]]
|
||||
address = "localhost:8081"
|
||||
address = "whoami-a:8080"
|
||||
|
||||
[tcp.services.whoami-b.loadBalancer]
|
||||
[[tcp.services.whoami-b.loadBalancer.servers]]
|
||||
address = "localhost:8082"
|
||||
address = "whoami-b:8080"
|
||||
|
||||
[tcp.services.whoami-no-cert.loadBalancer]
|
||||
[[tcp.services.whoami-no-cert.loadBalancer.servers]]
|
||||
address = "localhost:8083"
|
||||
address = "whoami-no-cert:8080"
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "fixtures/tcp/whoami-c.crt"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
[tcp.services.whoami-no-cert]
|
||||
[tcp.services.whoami-no-cert.loadBalancer]
|
||||
[[tcp.services.whoami-no-cert.loadBalancer.servers]]
|
||||
address = "localhost:8083"
|
||||
address = "whoami-no-cert:8080"
|
||||
|
||||
[tls.options]
|
||||
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
service = "whoami-a"
|
||||
entryPoints = [ "tcp" ]
|
||||
[tcp.routers.to-whoami-a.tls]
|
||||
passthrough=true
|
||||
passthrough = true
|
||||
|
||||
[tcp.routers.to-whoami-b]
|
||||
rule = "HostSNI(`whoami-b.test`)"
|
||||
service = "whoami-b"
|
||||
entryPoints = [ "tcp" ]
|
||||
[tcp.routers.to-whoami-b.tls]
|
||||
passthrough=true
|
||||
passthrough = true
|
||||
|
||||
[tcp.routers.to-whoami-no-cert]
|
||||
rule = "HostSNI(`whoami-c.test`)"
|
||||
|
@ -47,16 +47,17 @@
|
|||
[tcp.services]
|
||||
[tcp.services.whoami-no-tls.loadBalancer]
|
||||
[[tcp.services.whoami-no-tls.loadBalancer.servers]]
|
||||
address = "localhost:8084"
|
||||
address = "whoami-no-tls:8080"
|
||||
|
||||
[tcp.services.whoami-a.loadBalancer]
|
||||
[[tcp.services.whoami-a.loadBalancer.servers]]
|
||||
address = "localhost:8081"
|
||||
address = "whoami-a:8080"
|
||||
|
||||
[tcp.services.whoami-b.loadBalancer]
|
||||
[[tcp.services.whoami-b.loadBalancer.servers]]
|
||||
address = "localhost:8082"
|
||||
address = "whoami-b:8080"
|
||||
|
||||
[tcp.services.whoami-no-cert.loadBalancer]
|
||||
[[tcp.services.whoami-no-cert.loadBalancer.servers]]
|
||||
address = "localhost:8083"
|
||||
address = "whoami-no-cert:8080"
|
||||
|
||||
|
|
|
@ -27,4 +27,4 @@
|
|||
[tcp.services]
|
||||
[tcp.services.whoami-no-tls.loadBalancer]
|
||||
[[tcp.services.whoami-no-tls.loadBalancer.servers]]
|
||||
address = "localhost:8084"
|
||||
address = "whoami-no-tls:8080"
|
||||
|
|
|
@ -18,25 +18,24 @@
|
|||
## dynamic configuration ##
|
||||
[tcp]
|
||||
[tcp.routers]
|
||||
[tcp.routers.to-whoami-a]
|
||||
rule = "HostSNI(`whoami-a.test`)"
|
||||
[tcp.routers.to-whoami-b]
|
||||
rule = "HostSNI(`whoami-b.test`)"
|
||||
service = "whoami"
|
||||
entryPoints = [ "tcp" ]
|
||||
[tcp.routers.to-whoami-a.tls]
|
||||
[tcp.routers.to-whoami-b.tls]
|
||||
passthrough=true
|
||||
|
||||
[[tcp.services.whoami.weighted.services]]
|
||||
name="whoami-a"
|
||||
name="whoami-b"
|
||||
weight=3
|
||||
[[tcp.services.whoami.weighted.services]]
|
||||
name="whoami-b"
|
||||
name="whoami-ab"
|
||||
weight=1
|
||||
|
||||
[tcp.services.whoami-a.loadBalancer]
|
||||
[[tcp.services.whoami-a.loadBalancer.servers]]
|
||||
address = "localhost:8081"
|
||||
|
||||
[tcp.services.whoami-b.loadBalancer]
|
||||
[[tcp.services.whoami-b.loadBalancer.servers]]
|
||||
address = "localhost:8082"
|
||||
address = "whoami-b:8080"
|
||||
|
||||
[tcp.services.whoami-ab.loadBalancer]
|
||||
[[tcp.services.whoami-ab.loadBalancer.servers]]
|
||||
address = "whoami-ab:8080"
|
||||
|
|
|
@ -55,16 +55,16 @@
|
|||
[http.services.service1.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service2]
|
||||
[http.services.service2.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service2.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service3]
|
||||
[http.services.service3.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service3.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
|
|
@ -54,16 +54,16 @@
|
|||
[http.services.service1.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service2]
|
||||
[http.services.service2.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service2.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service3]
|
||||
[http.services.service3.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service3.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
|
|
@ -50,16 +50,16 @@
|
|||
[http.services.service1.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service2]
|
||||
[http.services.service2.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service2.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service3]
|
||||
[http.services.service3.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service3.loadBalancer.servers]]
|
||||
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// HealthCheck test suites (using libcompose).
|
||||
// HealthCheck test suites.
|
||||
type HealthCheckSuite struct {
|
||||
BaseSuite
|
||||
whoami1IP string
|
||||
|
@ -24,12 +24,12 @@ type HealthCheckSuite struct {
|
|||
|
||||
func (s *HealthCheckSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "healthcheck")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.whoami1IP = s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
s.whoami2IP = s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
s.whoami3IP = s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress
|
||||
s.whoami4IP = s.composeProject.Container(c, "whoami4").NetworkSettings.IPAddress
|
||||
s.whoami1IP = s.getComposeServiceIP(c, "whoami1")
|
||||
s.whoami2IP = s.getComposeServiceIP(c, "whoami2")
|
||||
s.whoami3IP = s.getComposeServiceIP(c, "whoami3")
|
||||
s.whoami4IP = s.getComposeServiceIP(c, "whoami4")
|
||||
}
|
||||
|
||||
func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
@ -90,7 +90,7 @@ func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
|
|||
|
||||
// Check if the service with bad health check (whoami2) never respond.
|
||||
err = try.Request(frontendReq, 2*time.Second, try.BodyContains(s.whoami2IP))
|
||||
c.Assert(err, checker.Not(checker.IsNil))
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
// TODO validate : run on 80
|
||||
resp, err := http.Get("http://127.0.0.1:8000/")
|
||||
|
|
|
@ -13,9 +13,7 @@ type HostResolverSuite struct{ BaseSuite }
|
|||
|
||||
func (s *HostResolverSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "hostresolver")
|
||||
|
||||
s.composeProject.Start(c)
|
||||
s.composeProject.Container(c, "server1")
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *HostResolverSuite) TestSimpleConfig(c *check.C) {
|
||||
|
@ -48,7 +46,7 @@ func (s *HostResolverSuite) TestSimpleConfig(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
req.Host = test.host
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(test.status), try.HasBody())
|
||||
err = try.Request(req, 1*time.Second, try.StatusCodeIs(test.status), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1063,13 +1063,13 @@ func (s *HTTPSSuite) TestEntryPointHttpsRedirectAndPathModification(c *check.C)
|
|||
for _, test := range testCases {
|
||||
sourceURL := fmt.Sprintf("http://127.0.0.1:8888%s", test.path)
|
||||
for _, host := range test.hosts {
|
||||
req, err := http.NewRequest("GET", sourceURL, nil)
|
||||
req, err := http.NewRequest(http.MethodGet, sourceURL, nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = host
|
||||
|
||||
resp, err := client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer resp.Body.Close()
|
||||
resp.Body.Close()
|
||||
|
||||
location := resp.Header.Get("Location")
|
||||
expected := fmt.Sprintf("https://%s:8443%s", host, test.path)
|
||||
|
|
|
@ -3,9 +3,9 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -14,17 +14,23 @@ import (
|
|||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
composeapi "github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/fatih/structs"
|
||||
"github.com/go-check/check"
|
||||
compose "github.com/libkermit/compose/check"
|
||||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
var (
|
||||
integration = flag.Bool("integration", false, "run integration tests")
|
||||
container = flag.Bool("container", false, "run container integration tests")
|
||||
host = flag.Bool("host", false, "run host integration tests")
|
||||
showLog = flag.Bool("tlog", false, "always show Traefik logs")
|
||||
)
|
||||
|
||||
|
@ -34,45 +40,39 @@ func Test(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
if *container {
|
||||
// tests launched from a container
|
||||
check.Suite(&AccessLogSuite{})
|
||||
check.Suite(&AcmeSuite{})
|
||||
check.Suite(&EtcdSuite{})
|
||||
check.Suite(&ConsulSuite{})
|
||||
check.Suite(&ConsulCatalogSuite{})
|
||||
check.Suite(&DockerComposeSuite{})
|
||||
check.Suite(&DockerSuite{})
|
||||
check.Suite(&ErrorPagesSuite{})
|
||||
check.Suite(&FileSuite{})
|
||||
check.Suite(&GRPCSuite{})
|
||||
check.Suite(&HealthCheckSuite{})
|
||||
check.Suite(&HeadersSuite{})
|
||||
check.Suite(&HostResolverSuite{})
|
||||
check.Suite(&HTTPSuite{})
|
||||
check.Suite(&HTTPSSuite{})
|
||||
check.Suite(&KeepAliveSuite{})
|
||||
check.Suite(&LogRotationSuite{})
|
||||
check.Suite(&MarathonSuite{})
|
||||
check.Suite(&MarathonSuite15{})
|
||||
check.Suite(&RateLimitSuite{})
|
||||
check.Suite(&RedisSuite{})
|
||||
check.Suite(&RestSuite{})
|
||||
check.Suite(&RetrySuite{})
|
||||
check.Suite(&SimpleSuite{})
|
||||
check.Suite(&TimeoutSuite{})
|
||||
check.Suite(&TLSClientHeadersSuite{})
|
||||
check.Suite(&TracingSuite{})
|
||||
check.Suite(&UDPSuite{})
|
||||
check.Suite(&WebsocketSuite{})
|
||||
check.Suite(&ZookeeperSuite{})
|
||||
}
|
||||
if *host {
|
||||
// tests launched from the host
|
||||
check.Suite(&K8sSuite{})
|
||||
check.Suite(&ProxyProtocolSuite{})
|
||||
check.Suite(&TCPSuite{})
|
||||
}
|
||||
check.Suite(&AccessLogSuite{})
|
||||
check.Suite(&AcmeSuite{})
|
||||
check.Suite(&ConsulCatalogSuite{})
|
||||
check.Suite(&ConsulSuite{})
|
||||
check.Suite(&DockerComposeSuite{})
|
||||
check.Suite(&DockerSuite{})
|
||||
check.Suite(&ErrorPagesSuite{})
|
||||
check.Suite(&EtcdSuite{})
|
||||
check.Suite(&FileSuite{})
|
||||
check.Suite(&GRPCSuite{})
|
||||
check.Suite(&HeadersSuite{})
|
||||
check.Suite(&HealthCheckSuite{})
|
||||
check.Suite(&HostResolverSuite{})
|
||||
check.Suite(&HTTPSSuite{})
|
||||
check.Suite(&HTTPSuite{})
|
||||
check.Suite(&K8sSuite{})
|
||||
check.Suite(&KeepAliveSuite{})
|
||||
check.Suite(&LogRotationSuite{})
|
||||
check.Suite(&MarathonSuite15{})
|
||||
check.Suite(&MarathonSuite{})
|
||||
check.Suite(&ProxyProtocolSuite{})
|
||||
check.Suite(&RateLimitSuite{})
|
||||
check.Suite(&RedisSuite{})
|
||||
check.Suite(&RestSuite{})
|
||||
check.Suite(&RetrySuite{})
|
||||
check.Suite(&SimpleSuite{})
|
||||
check.Suite(&TCPSuite{})
|
||||
check.Suite(&TimeoutSuite{})
|
||||
check.Suite(&TLSClientHeadersSuite{})
|
||||
check.Suite(&TracingSuite{})
|
||||
check.Suite(&UDPSuite{})
|
||||
check.Suite(&WebsocketSuite{})
|
||||
check.Suite(&ZookeeperSuite{})
|
||||
|
||||
check.TestingT(t)
|
||||
}
|
||||
|
@ -80,36 +80,72 @@ func Test(t *testing.T) {
|
|||
var traefikBinary = "../dist/traefik"
|
||||
|
||||
type BaseSuite struct {
|
||||
composeProject *compose.Project
|
||||
composeProject *types.Project
|
||||
dockerComposeService composeapi.Service
|
||||
dockerClient *client.Client
|
||||
}
|
||||
|
||||
func (s *BaseSuite) TearDownSuite(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
if s.composeProject != nil && s.dockerComposeService != nil {
|
||||
s.composeDown(c)
|
||||
}
|
||||
}
|
||||
|
||||
// createComposeProject creates the docker compose project stored as a field in the BaseSuite.
|
||||
// This method should be called before starting and/or stopping compose services.
|
||||
func (s *BaseSuite) createComposeProject(c *check.C, name string) {
|
||||
projectName := fmt.Sprintf("integration-test-%s", name)
|
||||
projectName := fmt.Sprintf("traefik-integration-test-%s", name)
|
||||
composeFile := fmt.Sprintf("resources/compose/%s.yml", name)
|
||||
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
var err error
|
||||
s.dockerClient, err = client.NewClientWithOpts()
|
||||
c.Assert(err, checker.IsNil)
|
||||
for _, addr := range addrs {
|
||||
ip, _, err := net.ParseCIDR(addr.String())
|
||||
c.Assert(err, checker.IsNil)
|
||||
if !ip.IsLoopback() && ip.To4() != nil {
|
||||
_ = os.Setenv("DOCKER_HOST_IP", ip.String())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
s.composeProject = compose.CreateProject(c, projectName, composeFile)
|
||||
s.dockerComposeService = compose.NewComposeService(s.dockerClient, &configfile.ConfigFile{})
|
||||
ops, err := cli.NewProjectOptions([]string{composeFile}, cli.WithName(projectName))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
s.composeProject, err = cli.ProjectFromOptions(ops)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func withConfigFile(file string) string {
|
||||
return "--configFile=" + file
|
||||
// composeUp starts the given services of the current docker compose project, if they are not already started.
|
||||
// Already running services are not affected (i.e. not stopped).
|
||||
func (s *BaseSuite) composeUp(c *check.C, services ...string) {
|
||||
c.Assert(s.composeProject, check.NotNil)
|
||||
c.Assert(s.dockerComposeService, check.NotNil)
|
||||
|
||||
// We use Create and Restart instead of Up, because the only option that actually works to control which containers
|
||||
// are started is within the RestartOptions.
|
||||
err := s.dockerComposeService.Create(context.Background(), s.composeProject, composeapi.CreateOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.dockerComposeService.Restart(context.Background(), s.composeProject, composeapi.RestartOptions{Services: services})
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// composeStop stops the given services of the current docker compose project and removes the corresponding containers.
|
||||
func (s *BaseSuite) composeStop(c *check.C, services ...string) {
|
||||
c.Assert(s.dockerComposeService, check.NotNil)
|
||||
c.Assert(s.composeProject, check.NotNil)
|
||||
|
||||
err := s.dockerComposeService.Stop(context.Background(), s.composeProject, composeapi.StopOptions{Services: services})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.dockerComposeService.Remove(context.Background(), s.composeProject, composeapi.RemoveOptions{
|
||||
Services: services,
|
||||
Force: true,
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// composeDown stops all compose project services and removes the corresponding containers.
|
||||
func (s *BaseSuite) composeDown(c *check.C) {
|
||||
c.Assert(s.dockerComposeService, check.NotNil)
|
||||
c.Assert(s.composeProject, check.NotNil)
|
||||
|
||||
err := s.dockerComposeService.Down(context.Background(), s.composeProject.Name, composeapi.DownOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
|
||||
|
@ -134,6 +170,7 @@ func (s *BaseSuite) traefikCmd(args ...string) (*exec.Cmd, func(*check.C)) {
|
|||
return cmd, func(c *check.C) {
|
||||
if c.Failed() || *showLog {
|
||||
s.displayLogK3S(c)
|
||||
s.displayLogCompose(c)
|
||||
s.displayTraefikLog(c, out)
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +190,25 @@ func (s *BaseSuite) displayLogK3S(c *check.C) {
|
|||
log.WithoutContext().Println()
|
||||
}
|
||||
|
||||
func (s *BaseSuite) displayLogCompose(c *check.C) {
|
||||
if s.dockerComposeService == nil || s.composeProject == nil {
|
||||
log.WithoutContext().Infof("%s: No docker compose logs.", c.TestName())
|
||||
return
|
||||
}
|
||||
|
||||
log.WithoutContext().Infof("%s: docker compose logs: ", c.TestName())
|
||||
|
||||
logWriter := log.WithoutContext().WriterLevel(log.GetLevel())
|
||||
logConsumer := formatter.NewLogConsumer(context.Background(), logWriter, false, true)
|
||||
|
||||
err := s.dockerComposeService.Logs(context.Background(), s.composeProject.Name, logConsumer, composeapi.LogOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
log.WithoutContext().Println()
|
||||
log.WithoutContext().Println("################################")
|
||||
log.WithoutContext().Println()
|
||||
}
|
||||
|
||||
func (s *BaseSuite) displayTraefikLog(c *check.C, output *bytes.Buffer) {
|
||||
if output == nil || output.Len() == 0 {
|
||||
log.WithoutContext().Infof("%s: No Traefik logs.", c.TestName())
|
||||
|
@ -168,6 +224,7 @@ func (s *BaseSuite) getDockerHost() string {
|
|||
// Default docker socket
|
||||
dockerHost = "unix:///var/run/docker.sock"
|
||||
}
|
||||
|
||||
return dockerHost
|
||||
}
|
||||
|
||||
|
@ -192,3 +249,38 @@ func (s *BaseSuite) adaptFile(c *check.C, path string, tempObjects interface{})
|
|||
|
||||
return tmpFile.Name()
|
||||
}
|
||||
|
||||
func (s *BaseSuite) getComposeServiceIP(c *check.C, name string) string {
|
||||
filter := filters.NewArgs(
|
||||
filters.Arg("label", fmt.Sprintf("%s=%s", composeapi.ProjectLabel, s.composeProject.Name)),
|
||||
filters.Arg("label", fmt.Sprintf("%s=%s", composeapi.ServiceLabel, name)),
|
||||
)
|
||||
|
||||
containers, err := s.dockerClient.ContainerList(context.Background(), dockertypes.ContainerListOptions{Filters: filter})
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(containers, checker.HasLen, 1)
|
||||
|
||||
networkNames := s.composeProject.NetworkNames()
|
||||
c.Assert(networkNames, checker.HasLen, 1)
|
||||
|
||||
network := s.composeProject.Networks[networkNames[0]]
|
||||
return containers[0].NetworkSettings.Networks[network.Name].IPAddress
|
||||
}
|
||||
|
||||
func (s *BaseSuite) getContainerIP(c *check.C, name string) string {
|
||||
container, err := s.dockerClient.ContainerInspect(context.Background(), name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(container.NetworkSettings.Networks, check.NotNil)
|
||||
|
||||
for _, network := range container.NetworkSettings.Networks {
|
||||
return network.IPAddress
|
||||
}
|
||||
|
||||
// Should never happen.
|
||||
c.Error("No network found")
|
||||
return ""
|
||||
}
|
||||
|
||||
func withConfigFile(file string) string {
|
||||
return "--configFile=" + file
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ type K8sSuite struct{ BaseSuite }
|
|||
|
||||
func (s *K8sSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "k8s")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
abs, err := filepath.Abs("./fixtures/k8s/config.skip/kubeconfig.yaml")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -44,7 +44,7 @@ func (s *K8sSuite) SetUpSuite(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *K8sSuite) TearDownSuite(c *check.C) {
|
||||
s.composeProject.Stop(c)
|
||||
s.composeDown(c)
|
||||
|
||||
generatedFiles := []string{
|
||||
"./fixtures/k8s/config.skip/kubeconfig.yaml",
|
||||
|
@ -56,8 +56,7 @@ func (s *K8sSuite) TearDownSuite(c *check.C) {
|
|||
}
|
||||
|
||||
for _, filename := range generatedFiles {
|
||||
err := os.Remove(filename)
|
||||
if err != nil {
|
||||
if err := os.Remove(filename); err != nil {
|
||||
log.WithoutContext().Warning(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,17 +13,38 @@ import (
|
|||
|
||||
"github.com/go-check/check"
|
||||
"github.com/traefik/traefik/v2/integration/try"
|
||||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
const (
|
||||
traefikTestLogFileRotated = traefikTestLogFile + ".rotated"
|
||||
traefikTestAccessLogFileRotated = traefikTestAccessLogFile + ".rotated"
|
||||
)
|
||||
|
||||
// Log rotation integration test suite.
|
||||
type LogRotationSuite struct{ BaseSuite }
|
||||
|
||||
func (s *LogRotationSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "access_log")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
s.composeProject.Container(c, "server1")
|
||||
func (s *LogRotationSuite) TearDownSuite(c *check.C) {
|
||||
s.composeDown(c)
|
||||
|
||||
generatedFiles := []string{
|
||||
traefikTestLogFile,
|
||||
traefikTestLogFileRotated,
|
||||
traefikTestAccessLogFile,
|
||||
traefikTestAccessLogFileRotated,
|
||||
}
|
||||
|
||||
for _, filename := range generatedFiles {
|
||||
if err := os.Remove(filename); err != nil {
|
||||
log.WithoutContext().Warning(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LogRotationSuite) TestAccessLogRotation(c *check.C) {
|
||||
|
@ -36,8 +57,6 @@ func (s *LogRotationSuite) TestAccessLogRotation(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
defer os.Remove(traefikTestAccessLogFile)
|
||||
|
||||
// Verify Traefik started ok
|
||||
verifyEmptyErrorLog(c, "traefik.log")
|
||||
|
||||
|
@ -52,7 +71,7 @@ func (s *LogRotationSuite) TestAccessLogRotation(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Rename access log
|
||||
err = os.Rename(traefikTestAccessLogFile, traefikTestAccessLogFile+".rotated")
|
||||
err = os.Rename(traefikTestAccessLogFile, traefikTestAccessLogFileRotated)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// in the midst of the requests, issue SIGUSR1 signal to server process
|
||||
|
@ -66,8 +85,8 @@ func (s *LogRotationSuite) TestAccessLogRotation(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Verify access.log.rotated output as expected
|
||||
logAccessLogFile(c, traefikTestAccessLogFile+".rotated")
|
||||
lineCount := verifyLogLines(c, traefikTestAccessLogFile+".rotated", 0, true)
|
||||
logAccessLogFile(c, traefikTestAccessLogFileRotated)
|
||||
lineCount := verifyLogLines(c, traefikTestAccessLogFileRotated, 0, true)
|
||||
c.Assert(lineCount, checker.GreaterOrEqualThan, 1)
|
||||
|
||||
// make sure that the access log file is at least created before we do assertions on it
|
||||
|
@ -95,12 +114,10 @@ func (s *LogRotationSuite) TestTraefikLogRotation(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
defer os.Remove(traefikTestAccessLogFile)
|
||||
|
||||
waitForTraefik(c, "server1")
|
||||
|
||||
// Rename traefik log
|
||||
err = os.Rename(traefikTestLogFile, traefikTestLogFile+".rotated")
|
||||
err = os.Rename(traefikTestLogFile, traefikTestLogFileRotated)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// issue SIGUSR1 signal to server process
|
||||
|
@ -118,7 +135,7 @@ func (s *LogRotationSuite) TestTraefikLogRotation(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// we have at least 6 lines in traefik.log.rotated
|
||||
lineCount := verifyLogLines(c, traefikTestLogFile+".rotated", 0, false)
|
||||
lineCount := verifyLogLines(c, traefikTestLogFileRotated, 0, false)
|
||||
|
||||
// GreaterOrEqualThan used to ensure test doesn't break
|
||||
// If more log entries are output on startup
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -12,7 +11,7 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Marathon test suites (using libcompose).
|
||||
// Marathon test suites.
|
||||
type MarathonSuite15 struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
|
@ -20,53 +19,15 @@ type MarathonSuite15 struct {
|
|||
|
||||
func (s *MarathonSuite15) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "marathon15")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
marathonIPAddr := s.composeProject.Container(c, containerNameMarathon).NetworkSettings.IPAddress
|
||||
c.Assert(marathonIPAddr, checker.Not(checker.HasLen), 0)
|
||||
s.marathonURL = "http://" + marathonIPAddr + ":8080"
|
||||
s.marathonURL = "http://" + containerNameMarathon + ":8080"
|
||||
|
||||
// Wait for Marathon readiness prior to creating the client so that we
|
||||
// don't run into the "all cluster members down" state right from the
|
||||
// start.
|
||||
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Add entry for Mesos slave container IP address in the hosts file so
|
||||
// that Traefik can properly forward traffic.
|
||||
// This is necessary as long as we are still using the docker-compose v1
|
||||
// spec. Once we switch to v2 or higher, we can have both the test/builder
|
||||
// container and the Mesos slave container join the same custom network and
|
||||
// enjoy DNS-discoverable container host names.
|
||||
mesosSlaveIPAddr := s.composeProject.Container(c, containerNameMesosSlave).NetworkSettings.IPAddress
|
||||
c.Assert(mesosSlaveIPAddr, checker.Not(checker.HasLen), 0)
|
||||
err = s.extendDockerHostsFile(containerNameMesosSlave, mesosSlaveIPAddr)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// extendDockerHostsFile extends the hosts file (/etc/hosts) by the given
|
||||
// host/IP address mapping if we are running inside a container.
|
||||
func (s *MarathonSuite15) extendDockerHostsFile(host, ipAddr string) error {
|
||||
const hostsFile = "/etc/hosts"
|
||||
|
||||
// Determine if the run inside a container. The most reliable way to
|
||||
// do this is to inject an indicator, which we do in terms of an
|
||||
// environment variable.
|
||||
// (See also https://groups.google.com/d/topic/docker-user/JOGE7AnJ3Gw/discussion.)
|
||||
if os.Getenv("CONTAINER") == "DOCKER" {
|
||||
// We are running inside a container -- extend the hosts file.
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = file.WriteString(fmt.Sprintf("%s\t%s\n", ipAddr, host)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MarathonSuite15) TestConfigurationUpdate(c *check.C) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -12,12 +11,9 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
const (
|
||||
containerNameMesosSlave = "mesos-slave"
|
||||
containerNameMarathon = "marathon"
|
||||
)
|
||||
const containerNameMarathon = "marathon"
|
||||
|
||||
// Marathon test suites (using libcompose).
|
||||
// Marathon test suites.
|
||||
type MarathonSuite struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
|
@ -25,53 +21,15 @@ type MarathonSuite struct {
|
|||
|
||||
func (s *MarathonSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "marathon")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
marathonIPAddr := s.composeProject.Container(c, containerNameMarathon).NetworkSettings.IPAddress
|
||||
c.Assert(marathonIPAddr, checker.Not(checker.HasLen), 0)
|
||||
s.marathonURL = "http://" + marathonIPAddr + ":8080"
|
||||
s.marathonURL = "http://" + containerNameMarathon + ":8080"
|
||||
|
||||
// Wait for Marathon readiness prior to creating the client so that we
|
||||
// don't run into the "all cluster members down" state right from the
|
||||
// start.
|
||||
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Add entry for Mesos slave container IP address in the hosts file so
|
||||
// that Traefik can properly forward traffic.
|
||||
// This is necessary as long as we are still using the docker-compose v1
|
||||
// spec. Once we switch to v2 or higher, we can have both the test/builder
|
||||
// container and the Mesos slave container join the same custom network and
|
||||
// enjoy DNS-discoverable container host names.
|
||||
mesosSlaveIPAddr := s.composeProject.Container(c, containerNameMesosSlave).NetworkSettings.IPAddress
|
||||
c.Assert(mesosSlaveIPAddr, checker.Not(checker.HasLen), 0)
|
||||
err = s.extendDockerHostsFile(containerNameMesosSlave, mesosSlaveIPAddr)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// extendDockerHostsFile extends the hosts file (/etc/hosts) by the given
|
||||
// host/IP address mapping if we are running inside a container.
|
||||
func (s *MarathonSuite) extendDockerHostsFile(host, ipAddr string) error {
|
||||
const hostsFile = "/etc/hosts"
|
||||
|
||||
// Determine if the run inside a container. The most reliable way to
|
||||
// do this is to inject an indicator, which we do in terms of an
|
||||
// environment variable.
|
||||
// (See also https://groups.google.com/d/topic/docker-user/JOGE7AnJ3Gw/discussion.)
|
||||
if os.Getenv("CONTAINER") == "DOCKER" {
|
||||
// We are running inside a container -- extend the hosts file.
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = file.WriteString(fmt.Sprintf("%s\t%s\n", ipAddr, host)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deployApplication(c *check.C, client marathon.Marathon, application *marathon.Application) {
|
||||
|
|
|
@ -10,22 +10,27 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
type ProxyProtocolSuite struct{ BaseSuite }
|
||||
type ProxyProtocolSuite struct {
|
||||
BaseSuite
|
||||
gatewayIP string
|
||||
haproxyIP string
|
||||
whoamiIP string
|
||||
}
|
||||
|
||||
func (s *ProxyProtocolSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "proxy-protocol")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.gatewayIP = s.getContainerIP(c, "traefik")
|
||||
s.haproxyIP = s.getComposeServiceIP(c, "haproxy")
|
||||
s.whoamiIP = s.getComposeServiceIP(c, "whoami")
|
||||
}
|
||||
|
||||
func (s *ProxyProtocolSuite) TestProxyProtocolTrusted(c *check.C) {
|
||||
gatewayIP := s.composeProject.Container(c, "haproxy").NetworkSettings.Gateway
|
||||
haproxyIP := s.composeProject.Container(c, "haproxy").NetworkSettings.IPAddress
|
||||
whoamiIP := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
|
||||
file := s.adaptFile(c, "fixtures/proxy-protocol/with.toml", struct {
|
||||
HaproxyIP string
|
||||
WhoamiIP string
|
||||
}{HaproxyIP: haproxyIP, WhoamiIP: whoamiIP})
|
||||
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -34,21 +39,17 @@ func (s *ProxyProtocolSuite) TestProxyProtocolTrusted(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://"+haproxyIP+"/whoami", 1*time.Second,
|
||||
err = try.GetRequest("http://"+s.haproxyIP+"/whoami", 1*time.Second,
|
||||
try.StatusCodeIs(http.StatusOK),
|
||||
try.BodyContains("X-Forwarded-For: "+gatewayIP))
|
||||
try.BodyContains("X-Forwarded-For: "+s.gatewayIP))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ProxyProtocolSuite) TestProxyProtocolV2Trusted(c *check.C) {
|
||||
gatewayIP := s.composeProject.Container(c, "haproxy").NetworkSettings.Gateway
|
||||
haproxyIP := s.composeProject.Container(c, "haproxy").NetworkSettings.IPAddress
|
||||
whoamiIP := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
|
||||
file := s.adaptFile(c, "fixtures/proxy-protocol/with.toml", struct {
|
||||
HaproxyIP string
|
||||
WhoamiIP string
|
||||
}{HaproxyIP: haproxyIP, WhoamiIP: whoamiIP})
|
||||
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -57,20 +58,17 @@ func (s *ProxyProtocolSuite) TestProxyProtocolV2Trusted(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://"+haproxyIP+":81/whoami", 1*time.Second,
|
||||
err = try.GetRequest("http://"+s.haproxyIP+":81/whoami", 1*time.Second,
|
||||
try.StatusCodeIs(http.StatusOK),
|
||||
try.BodyContains("X-Forwarded-For: "+gatewayIP))
|
||||
try.BodyContains("X-Forwarded-For: "+s.gatewayIP))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ProxyProtocolSuite) TestProxyProtocolNotTrusted(c *check.C) {
|
||||
haproxyIP := s.composeProject.Container(c, "haproxy").NetworkSettings.IPAddress
|
||||
whoamiIP := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
|
||||
file := s.adaptFile(c, "fixtures/proxy-protocol/without.toml", struct {
|
||||
HaproxyIP string
|
||||
WhoamiIP string
|
||||
}{HaproxyIP: haproxyIP, WhoamiIP: whoamiIP})
|
||||
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -79,20 +77,17 @@ func (s *ProxyProtocolSuite) TestProxyProtocolNotTrusted(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://"+haproxyIP+"/whoami", 1*time.Second,
|
||||
err = try.GetRequest("http://"+s.haproxyIP+"/whoami", 1*time.Second,
|
||||
try.StatusCodeIs(http.StatusOK),
|
||||
try.BodyContains("X-Forwarded-For: "+haproxyIP))
|
||||
try.BodyContains("X-Forwarded-For: "+s.haproxyIP))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ProxyProtocolSuite) TestProxyProtocolV2NotTrusted(c *check.C) {
|
||||
haproxyIP := s.composeProject.Container(c, "haproxy").NetworkSettings.IPAddress
|
||||
whoamiIP := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
|
||||
file := s.adaptFile(c, "fixtures/proxy-protocol/without.toml", struct {
|
||||
HaproxyIP string
|
||||
WhoamiIP string
|
||||
}{HaproxyIP: haproxyIP, WhoamiIP: whoamiIP})
|
||||
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -101,8 +96,8 @@ func (s *ProxyProtocolSuite) TestProxyProtocolV2NotTrusted(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://"+haproxyIP+":81/whoami", 1*time.Second,
|
||||
err = try.GetRequest("http://"+s.haproxyIP+":81/whoami", 1*time.Second,
|
||||
try.StatusCodeIs(http.StatusOK),
|
||||
try.BodyContains("X-Forwarded-For: "+haproxyIP))
|
||||
try.BodyContains("X-Forwarded-For: "+s.haproxyIP))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ type RateLimitSuite struct {
|
|||
|
||||
func (s *RateLimitSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "ratelimit")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.ServerIP = s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
s.ServerIP = s.getComposeServiceIP(c, "whoami1")
|
||||
}
|
||||
|
||||
func (s *RateLimitSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package integration
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -18,20 +19,22 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Redis test suites (using libcompose).
|
||||
// Redis test suites.
|
||||
type RedisSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
kvClient store.Store
|
||||
redisAddr string
|
||||
}
|
||||
|
||||
func (s *RedisSuite) setupStore(c *check.C) {
|
||||
s.createComposeProject(c, "redis")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.redisAddr = net.JoinHostPort(s.getComposeServiceIP(c, "redis"), "6379")
|
||||
redis.Register()
|
||||
kv, err := valkeyrie.NewStore(
|
||||
store.REDIS,
|
||||
[]string{s.composeProject.Container(c, "redis").NetworkSettings.IPAddress + ":6379"},
|
||||
[]string{s.redisAddr},
|
||||
&store.Config{
|
||||
ConnectionTimeout: 10 * time.Second,
|
||||
},
|
||||
|
@ -46,20 +49,10 @@ func (s *RedisSuite) setupStore(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *RedisSuite) TearDownTest(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RedisSuite) TearDownSuite(c *check.C) {}
|
||||
|
||||
func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
|
||||
s.setupStore(c)
|
||||
|
||||
address := s.composeProject.Container(c, "redis").NetworkSettings.IPAddress + ":6379"
|
||||
file := s.adaptFile(c, "fixtures/redis/simple.toml", struct{ RedisAddress string }{address})
|
||||
file := s.adaptFile(c, "fixtures/redis/simple.toml", struct{ RedisAddress string }{s.redisAddr})
|
||||
defer os.Remove(file)
|
||||
|
||||
data := map[string]string{
|
||||
|
|
|
@ -1,77 +1,91 @@
|
|||
server0:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-server0.entryPoints=web
|
||||
- traefik.http.routers.rt-server0.rule=Path("/test")
|
||||
- traefik.http.services.service1.loadbalancer.server.port=80
|
||||
server1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-server1.entryPoints=web
|
||||
- traefik.http.routers.rt-server1.rule=Host("frontend1.docker.local")
|
||||
- traefik.http.routers.rt-server1.service=service1
|
||||
- traefik.http.services.service1.loadbalancer.server.port=80
|
||||
server2:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-server2.entryPoints=web
|
||||
- traefik.http.routers.rt-server2.rule=Host("frontend2.docker.local")
|
||||
- traefik.http.services.service2.loadbalancer.server.port=80
|
||||
server3:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-server3.entryPoints=web
|
||||
- traefik.http.routers.rt-server3.rule=Host("frontend2.docker.local")
|
||||
- traefik.http.services.service2.loadbalancer.server.port=80
|
||||
authFrontend:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-authFrontend.entryPoints=httpFrontendAuth
|
||||
- traefik.http.routers.rt-authFrontend.rule=Host("frontend.auth.docker.local")
|
||||
- traefik.http.routers.rt-authFrontend.middlewares=basicauth
|
||||
- traefik.http.middlewares.basicauth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
digestAuthMiddleware:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-digestAuthMiddleware.entryPoints=digestAuth
|
||||
- traefik.http.routers.rt-digestAuthMiddleware.rule=Host("entrypoint.digest.auth.docker.local")
|
||||
- traefik.http.routers.rt-digestAuthMiddleware.middlewares=digestauth
|
||||
- traefik.http.middlewares.digestauth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05, test2:traefik:518845800f9e2bfb1f1f740ec24f074e
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
frontendRedirect:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-frontendRedirect.entryPoints=frontendRedirect
|
||||
- traefik.http.routers.rt-frontendRedirect.rule=Path("/test")
|
||||
- traefik.http.routers.rt-frontendRedirect.middlewares=redirecthttp
|
||||
- traefik.http.middlewares.redirecthttp.redirectScheme.scheme=http
|
||||
- traefik.http.middlewares.redirecthttp.redirectScheme.port=8000
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
rateLimit:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-rateLimit.entryPoints=httpRateLimit
|
||||
- traefik.http.routers.rt-rateLimit.rule=Host("ratelimit.docker.local")
|
||||
- traefik.http.routers.rt-rateLimit.middlewares=rate
|
||||
- traefik.http.middlewares.rate.ratelimit
|
||||
- traefik.http.middlewares.rate.ratelimit.average=1
|
||||
- traefik.http.middlewares.rate.ratelimit.burst=2
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
frontendWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt-frontendWhitelist.entryPoints=web
|
||||
- traefik.http.routers.rt-frontendWhitelist.rule=Host("frontend.whitelist.docker.local")
|
||||
- traefik.http.routers.rt-frontendWhitelist.middlewares=wl
|
||||
- traefik.http.middlewares.wl.ipwhitelist.sourcerange=8.8.8.8/32
|
||||
- traefik.http.services.service3.loadbalancer.server.port=80
|
||||
version: "3.8"
|
||||
services:
|
||||
server0:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-server0.entryPoints: web
|
||||
traefik.http.routers.rt-server0.rule: Path(`/test`)
|
||||
traefik.http.services.service1.loadbalancer.server.port: 80
|
||||
|
||||
server1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-server1.entryPoints: web
|
||||
traefik.http.routers.rt-server1.rule: Host(`frontend1.docker.local`)
|
||||
traefik.http.routers.rt-server1.service: service1
|
||||
traefik.http.services.service1.loadbalancer.server.port: 80
|
||||
|
||||
server2:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-server2.entryPoints: web
|
||||
traefik.http.routers.rt-server2.rule: Host(`frontend2.docker.local`)
|
||||
traefik.http.services.service2.loadbalancer.server.port: 80
|
||||
|
||||
server3:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-server3.entryPoints: web
|
||||
traefik.http.routers.rt-server3.rule: Host(`frontend2.docker.local`)
|
||||
traefik.http.services.service2.loadbalancer.server.port: 80
|
||||
|
||||
authFrontend:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-authFrontend.entryPoints: httpFrontendAuth
|
||||
traefik.http.routers.rt-authFrontend.rule: Host(`frontend.auth.docker.local`)
|
||||
traefik.http.routers.rt-authFrontend.middlewares: basicauth
|
||||
traefik.http.middlewares.basicauth.basicauth.users: test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/
|
||||
traefik.http.services.service3.loadbalancer.server.port: 80
|
||||
|
||||
digestAuthMiddleware:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-digestAuthMiddleware.entryPoints: digestAuth
|
||||
traefik.http.routers.rt-digestAuthMiddleware.rule: Host(`entrypoint.digest.auth.docker.local`)
|
||||
traefik.http.routers.rt-digestAuthMiddleware.middlewares: digestauth
|
||||
traefik.http.middlewares.digestauth.digestauth.users: test:traefik:a2688e031edb4be6a3797f3882655c05, test2:traefik:518845800f9e2bfb1f1f740ec24f074e
|
||||
traefik.http.services.service3.loadbalancer.server.port: 80
|
||||
|
||||
frontendRedirect:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-frontendRedirect.entryPoints: frontendRedirect
|
||||
traefik.http.routers.rt-frontendRedirect.rule: Path(`/test`)
|
||||
traefik.http.routers.rt-frontendRedirect.middlewares: redirecthttp
|
||||
traefik.http.middlewares.redirecthttp.redirectScheme.scheme: http
|
||||
traefik.http.middlewares.redirecthttp.redirectScheme.port: 8000
|
||||
traefik.http.services.service3.loadbalancer.server.port: 80
|
||||
|
||||
rateLimit:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-rateLimit.entryPoints: httpRateLimit
|
||||
traefik.http.routers.rt-rateLimit.rule: Host(`ratelimit.docker.local`)
|
||||
traefik.http.routers.rt-rateLimit.middlewares: rate
|
||||
traefik.http.middlewares.rate.ratelimit.average: 1
|
||||
traefik.http.middlewares.rate.ratelimit.burst: 2
|
||||
traefik.http.services.service3.loadbalancer.server.port: 80
|
||||
|
||||
frontendWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt-frontendWhitelist.entryPoints: web
|
||||
traefik.http.routers.rt-frontendWhitelist.rule: Host(`frontend.whitelist.docker.local`)
|
||||
traefik.http.routers.rt-frontendWhitelist.middlewares: wl
|
||||
traefik.http.middlewares.wl.ipwhitelist.sourcerange: 8.8.8.8/32
|
||||
traefik.http.services.service3.loadbalancer.server.port: 80
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.router1.rule=PathPrefix("/whoami")
|
||||
- traefik.http.routers.router2.rule=PathPrefix("/whoami2")
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.router1.rule: PathPrefix(`/whoami`)
|
||||
traefik.http.routers.router2.rule: PathPrefix(`/whoami2`)
|
||||
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=false
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: false
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
consul:
|
||||
image: consul:1.6
|
||||
ports:
|
||||
- "8500:8500"
|
||||
version: "3.8"
|
||||
services:
|
||||
consul:
|
||||
image: consul:1.6
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,32 +1,37 @@
|
|||
consul:
|
||||
image: consul:1.6.2
|
||||
ports:
|
||||
- 8500:8500
|
||||
command: "agent -server -bootstrap -ui -client 0.0.0.0 -hcl 'connect { enabled = true }'"
|
||||
consul-agent:
|
||||
image: consul:1.6.2
|
||||
ports:
|
||||
- 8501:8500
|
||||
command: "agent -retry-join consul -client 0.0.0.0"
|
||||
links:
|
||||
- consul
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
hostname: whoami1
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
hostname: whoami2
|
||||
whoami3:
|
||||
image: traefik/whoami
|
||||
hostname: whoami3
|
||||
whoamitcp:
|
||||
image: traefik/whoamitcp
|
||||
hostname: whoamitcp
|
||||
connect:
|
||||
image: hashicorpnomad/uuid-api:v5
|
||||
links:
|
||||
- consul
|
||||
environment:
|
||||
PORT: 443
|
||||
BIND: 0.0.0.0
|
||||
CONSUL_HTTP_ADDR: http://consul:8500
|
||||
version: "3.8"
|
||||
services:
|
||||
consul:
|
||||
image: consul:1.6.2
|
||||
command: agent -server -bootstrap -ui -client 0.0.0.0 -hcl 'connect { enabled = true }'
|
||||
|
||||
consul-agent:
|
||||
image: consul:1.6.2
|
||||
command: agent -retry-join consul -client 0.0.0.0
|
||||
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
hostname: whoami1
|
||||
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
hostname: whoami2
|
||||
|
||||
whoami3:
|
||||
image: traefik/whoami
|
||||
hostname: whoami3
|
||||
|
||||
whoamitcp:
|
||||
image: traefik/whoamitcp
|
||||
hostname: whoamitcp
|
||||
|
||||
connect:
|
||||
image: hashicorpnomad/uuid-api:v5
|
||||
environment:
|
||||
PORT: 443
|
||||
BIND: 0.0.0.0
|
||||
CONSUL_HTTP_ADDR: http://consul:8500
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
43
integration/resources/compose/docker.yml
Normal file
43
integration/resources/compose/docker.yml
Normal file
|
@ -0,0 +1,43 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
simple:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blablabla" ]
|
||||
|
||||
withtcplabels:
|
||||
image: traefik/whoamitcp
|
||||
command: [ "-name", "my.super.host" ]
|
||||
labels:
|
||||
traefik.tcp.Routers.Super.Rule: HostSNI(`my.super.host`)
|
||||
traefik.tcp.Routers.Super.tls: true
|
||||
traefik.tcp.Services.Super.Loadbalancer.server.port: 8080
|
||||
|
||||
withlabels1:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blabla" ]
|
||||
labels:
|
||||
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
||||
|
||||
withlabels2:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blablabla" ]
|
||||
labels:
|
||||
traefik.http.Routers.SuperHost.Rule: Host(`my-super.host`)
|
||||
|
||||
withonelabelmissing:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blabla" ]
|
||||
labels:
|
||||
traefik.random.value: my.super.host
|
||||
|
||||
powpow:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blabla" ]
|
||||
labels:
|
||||
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
||||
traefik.http.Services.powpow.LoadBalancer.server.Port: 2375
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
|
@ -1,4 +1,12 @@
|
|||
nginx1:
|
||||
image: nginx:1.13.8-alpine
|
||||
nginx2:
|
||||
image: nginx:1.13.8-alpine
|
||||
version: "3.8"
|
||||
services:
|
||||
nginx1:
|
||||
image: nginx:1.13.8-alpine
|
||||
|
||||
nginx2:
|
||||
image: nginx:1.13.8-alpine
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
etcd:
|
||||
image: quay.io/coreos/etcd:v3.3.18
|
||||
command: etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2380
|
||||
ports:
|
||||
- "2379:2379"
|
||||
version: "3.8"
|
||||
services:
|
||||
etcd:
|
||||
image: quay.io/coreos/etcd:v3.3.18
|
||||
command: etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2380
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8881:80"
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8882:80"
|
||||
whoami3:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8883:80"
|
||||
whoami4:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8884:80"
|
||||
whoami5:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8885:80"
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami3:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami4:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami5:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami3:
|
||||
image: traefik/whoami
|
||||
whoami3:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami4:
|
||||
image: traefik/whoami
|
||||
whoami4:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
server1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.service1.loadbalancer.server.port=80
|
||||
- traefik.http.routers.router1.rule=Host("github.com")
|
||||
version: "3.8"
|
||||
services:
|
||||
server1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.services.service1.loadbalancer.server.port: 80
|
||||
traefik.http.routers.router1.rule: Host(`github.com`)
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
server:
|
||||
image: rancher/k3s:v1.18.20-k3s1
|
||||
command: server --disable-agent --no-deploy coredns --no-deploy servicelb --no-deploy traefik --no-deploy local-storage --no-deploy metrics-server --log /output/k3s.log
|
||||
environment:
|
||||
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||
- K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
|
||||
- K3S_KUBECONFIG_MODE=666
|
||||
volumes:
|
||||
- ../../fixtures/k8s/config.skip:/output
|
||||
- ../../fixtures/k8s:/var/lib/rancher/k3s/server/manifests
|
||||
ports:
|
||||
- 6443:6443
|
||||
version: "3.8"
|
||||
services:
|
||||
server:
|
||||
image: rancher/k3s:v1.18.20-k3s1
|
||||
command: server --disable-agent --no-deploy coredns --no-deploy servicelb --no-deploy traefik --no-deploy local-storage --no-deploy metrics-server --log /output/k3s.log --bind-address=server --tls-san=server
|
||||
environment:
|
||||
K3S_CLUSTER_SECRET: somethingtotallyrandom
|
||||
K3S_KUBECONFIG_OUTPUT: /output/kubeconfig.yaml
|
||||
K3S_KUBECONFIG_MODE: 666
|
||||
volumes:
|
||||
- ./fixtures/k8s/config.skip:/output
|
||||
- ./fixtures/k8s:/var/lib/rancher/k3s/server/manifests
|
||||
|
||||
node:
|
||||
image: rancher/k3s:v1.18.20-k3s1
|
||||
privileged: true
|
||||
links:
|
||||
- server
|
||||
environment:
|
||||
- K3S_URL=https://server:6443
|
||||
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||
node:
|
||||
image: rancher/k3s:v1.18.20-k3s1
|
||||
privileged: true
|
||||
environment:
|
||||
K3S_URL: https://server:6443
|
||||
K3S_CLUSTER_SECRET: somethingtotallyrandom
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,54 +1,60 @@
|
|||
zookeeper:
|
||||
image: zookeeper:3.4.10
|
||||
version: "3.8"
|
||||
services:
|
||||
zookeeper:
|
||||
image: zookeeper:3.4.10
|
||||
|
||||
mesos-master:
|
||||
links:
|
||||
- zookeeper
|
||||
image: mesosphere/mesos-master:1.0.1-2.0.93.ubuntu1404
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5050:5050"
|
||||
environment:
|
||||
- MESOS_HOSTNAME=mesos-master
|
||||
- MESOS_CLUSTER=local
|
||||
- MESOS_REGISTRY=in_memory
|
||||
- MESOS_LOG_DIR=/var/log
|
||||
- MESOS_WORK_DIR=/var/lib/mesos
|
||||
- MESOS_ZK=zk://zookeeper:2181/mesos
|
||||
mesos-master:
|
||||
image: mesosphere/mesos-master:1.0.1-2.0.93.ubuntu1404
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5050:5050"
|
||||
environment:
|
||||
MESOS_HOSTNAME: mesos-master
|
||||
MESOS_CLUSTER: local
|
||||
MESOS_REGISTRY: in_memory
|
||||
MESOS_LOG_DIR: /var/log
|
||||
MESOS_WORK_DIR: /var/lib/mesos
|
||||
MESOS_ZK: zk://zookeeper:2181/mesos
|
||||
|
||||
mesos-slave:
|
||||
links:
|
||||
- zookeeper
|
||||
- mesos-master
|
||||
image: mesosphere/mesos-slave-dind:0.3.0_mesos-1.0.1_docker-1.10.3_ubuntu-14.04.5
|
||||
privileged: true
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5051:5051"
|
||||
environment:
|
||||
- MESOS_HOSTNAME=mesos-slave
|
||||
- MESOS_CONTAINERIZERS=docker,mesos
|
||||
- MESOS_ISOLATOR=cgroups/cpu,cgroups/mem
|
||||
- MESOS_LOG_DIR=/var/log
|
||||
- MESOS_MASTER=zk://zookeeper:2181/mesos
|
||||
- MESOS_PORT=5051
|
||||
- MESOS_WORK_DIR=/var/lib/mesos
|
||||
- MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins
|
||||
- MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs
|
||||
- MESOS_DOCKER_STOP_TIMEOUT=60secs
|
||||
- MESOS_RESOURCES=cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]
|
||||
mesos-slave:
|
||||
image: docker:dind
|
||||
privileged: true
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5051:5051"
|
||||
# docker version in mesosphere/mesos-slave-dind:0.3.0_mesos-1.0.1_docker-1.10.3_ubuntu-14.04.5 is too old and can't
|
||||
# pull images on new kernels.
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- "(/usr/local/bin/dockerd-entrypoint.sh &); sleep 10; set -x; \
|
||||
docker -H unix:///var/run/docker.sock run -d --net=host --privileged \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /cgroup:/cgroup -v /sys:/sys \
|
||||
-v /usr/local/bin/docker:/usr/local/bin/docker \
|
||||
-e MESOS_HOSTNAME=mesos-slave \
|
||||
-e MESOS_CONTAINERIZERS=docker,mesos \
|
||||
-e MESOS_ISOLATOR=cgroups/cpu,cgroups/mem \
|
||||
-e MESOS_LOG_DIR=/var/log \
|
||||
-e MESOS_MASTER=zk://zookeeper:2181/mesos \
|
||||
-e MESOS_PORT=5051 \
|
||||
-e MESOS_WORK_DIR=/var/lib/mesos \
|
||||
-e MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins \
|
||||
-e MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs \
|
||||
-e MESOS_DOCKER_STOP_TIMEOUT=60secs \
|
||||
-e MESOS_RESOURCES='cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]' \
|
||||
mesosphere/mesos-slave:1.0.3; sleep 600"
|
||||
|
||||
marathon:
|
||||
links:
|
||||
- zookeeper
|
||||
- mesos-master
|
||||
- mesos-slave
|
||||
image: mesosphere/marathon:v1.3.12
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
extra_hosts:
|
||||
- "mesos-slave:172.17.0.1"
|
||||
environment:
|
||||
- MARATHON_ZK=zk://zookeeper:2181/marathon
|
||||
- MARATHON_MASTER=zk://zookeeper:2181/mesos
|
||||
marathon:
|
||||
image: mesosphere/marathon:v1.3.12
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
environment:
|
||||
MARATHON_ZK: zk://zookeeper:2181/marathon
|
||||
MARATHON_MASTER: zk://zookeeper:2181/mesos
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,55 +1,51 @@
|
|||
zookeeper:
|
||||
image: zookeeper:3.4.10
|
||||
version: "3.8"
|
||||
services:
|
||||
zookeeper:
|
||||
image: zookeeper:3.4.10
|
||||
|
||||
mesos-master:
|
||||
links:
|
||||
- zookeeper
|
||||
image: mesosphere/mesos-master:1.4.1
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5050:5050"
|
||||
environment:
|
||||
- MESOS_HOSTNAME=mesos-master
|
||||
- MESOS_CLUSTER=local
|
||||
- MESOS_REGISTRY=in_memory
|
||||
- MESOS_LOG_DIR=/var/log
|
||||
- MESOS_WORK_DIR=/var/lib/mesos
|
||||
- MESOS_ZK=zk://zookeeper:2181/mesos
|
||||
mesos-master:
|
||||
image: mesosphere/mesos-master:1.4.1
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5050:5050"
|
||||
environment:
|
||||
MESOS_HOSTNAME: mesos-master
|
||||
MESOS_CLUSTER: local
|
||||
MESOS_REGISTRY: in_memory
|
||||
MESOS_LOG_DIR: /var/log
|
||||
MESOS_WORK_DIR: /var/lib/mesos
|
||||
MESOS_ZK: zk://zookeeper:2181/mesos
|
||||
|
||||
mesos-slave:
|
||||
links:
|
||||
- zookeeper
|
||||
- mesos-master
|
||||
image: mesosphere/mesos-slave-dind:0.4.0_mesos-1.4.1_docker-17.05.0_ubuntu-16.04.3
|
||||
privileged: true
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5051:5051"
|
||||
environment:
|
||||
- MESOS_HOSTNAME=mesos-slave
|
||||
- MESOS_CONTAINERIZERS=docker,mesos
|
||||
- MESOS_ISOLATOR=cgroups/cpu,cgroups/mem
|
||||
- MESOS_LOG_DIR=/var/log
|
||||
- MESOS_MASTER=zk://zookeeper:2181/mesos
|
||||
- MESOS_PORT=5051
|
||||
- MESOS_WORK_DIR=/var/lib/mesos
|
||||
- MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins
|
||||
- MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs
|
||||
- MESOS_DOCKER_STOP_TIMEOUT=60secs
|
||||
- MESOS_RESOURCES=cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]
|
||||
- MESOS_SYSTEMD_ENABLE_SUPPORT=false
|
||||
mesos-slave:
|
||||
image: mesosphere/mesos-slave-dind:0.4.0_mesos-1.4.1_docker-17.05.0_ubuntu-16.04.3
|
||||
privileged: true
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5051:5051"
|
||||
environment:
|
||||
MESOS_HOSTNAME: mesos-slave
|
||||
MESOS_CONTAINERIZERS: docker,mesos
|
||||
MESOS_ISOLATOR: cgroups/cpu,cgroups/mem
|
||||
MESOS_LOG_DIR: /var/log
|
||||
MESOS_MASTER: zk://zookeeper:2181/mesos
|
||||
MESOS_PORT: 5051
|
||||
MESOS_WORK_DIR: /var/lib/mesos
|
||||
MESOS_EXECUTOR_REGISTRATION_TIMEOUT: 5mins
|
||||
MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD: 90secs
|
||||
MESOS_DOCKER_STOP_TIMEOUT: 60secs
|
||||
MESOS_RESOURCES: cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]
|
||||
MESOS_SYSTEMD_ENABLE_SUPPORT: false
|
||||
|
||||
marathon:
|
||||
links:
|
||||
- zookeeper
|
||||
- mesos-master
|
||||
- mesos-slave
|
||||
image: mesosphere/marathon:v1.5.9
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
extra_hosts:
|
||||
- "mesos-slave:172.17.0.1"
|
||||
environment:
|
||||
- MARATHON_ZK=zk://zookeeper:2181/marathon
|
||||
- MARATHON_MASTER=zk://zookeeper:2181/mesos
|
||||
marathon:
|
||||
image: mesosphere/marathon:v1.5.9
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
environment:
|
||||
MARATHON_ZK: zk://zookeeper:2181/marathon
|
||||
MARATHON_MASTER: zk://zookeeper:2181/mesos
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.http.Routers.RouterMini.Rule=PathPrefix("/whoami")
|
||||
- traefik.enable=true
|
||||
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.http.Routers.RouterMini.Rule: PathPrefix(`/whoami`)
|
||||
traefik.enable: true
|
||||
deploy:
|
||||
replicas: 2
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
pebble:
|
||||
image: letsencrypt/pebble:v2.3.1
|
||||
command: pebble --dnsserver ${DOCKER_HOST_IP}:5053
|
||||
ports:
|
||||
- 14000:14000
|
||||
environment:
|
||||
# https://github.com/letsencrypt/pebble#testing-at-full-speed
|
||||
- PEBBLE_VA_NOSLEEP=1
|
||||
# https://github.com/letsencrypt/pebble#invalid-anti-replay-nonce-errors
|
||||
- PEBBLE_WFE_NONCEREJECT=0
|
||||
version: "3.8"
|
||||
services:
|
||||
pebble:
|
||||
image: letsencrypt/pebble:v2.3.1
|
||||
command: pebble --dnsserver traefik:5053
|
||||
environment:
|
||||
# https://github.com/letsencrypt/pebble#testing-at-full-speed
|
||||
PEBBLE_VA_NOSLEEP: 1
|
||||
# https://github.com/letsencrypt/pebble#invalid-anti-replay-nonce-errors
|
||||
PEBBLE_WFE_NONCEREJECT: 0
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
haproxy:
|
||||
image: haproxy:2.2
|
||||
volumes:
|
||||
- ../haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
|
||||
version: "3.8"
|
||||
services:
|
||||
haproxy:
|
||||
image: haproxy:2.2
|
||||
volumes:
|
||||
- ./resources/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
|
||||
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
redis:
|
||||
image: redis:5.0
|
||||
ports:
|
||||
- "6379:6379"
|
||||
version: "3.8"
|
||||
services:
|
||||
redis:
|
||||
image: redis:5.0
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
whoami:
|
||||
image: traefik/whoami
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8881:80"
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
whoami:
|
||||
image: traefik/whoami
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
whoami1:
|
||||
image: traefik/whoami
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami2:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,38 +1,39 @@
|
|||
whoami-a:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-a -certFile /certs/whoami-a.crt -keyFile /certs/whoami-a.key
|
||||
volumes:
|
||||
- ../../fixtures/tcp:/certs
|
||||
ports:
|
||||
- "8081:8080"
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami-a:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-a -certFile /certs/whoami-a.crt -keyFile /certs/whoami-a.key
|
||||
volumes:
|
||||
- ./fixtures/tcp:/certs
|
||||
|
||||
whoami-b:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-b -certFile /certs/whoami-b.crt -keyFile /certs/whoami-b.key
|
||||
volumes:
|
||||
- ../../fixtures/tcp:/certs
|
||||
ports:
|
||||
- "8082:8080"
|
||||
whoami-b:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-b -certFile /certs/whoami-b.crt -keyFile /certs/whoami-b.key
|
||||
volumes:
|
||||
- ./fixtures/tcp:/certs
|
||||
|
||||
whoami-no-cert:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-no-cert
|
||||
ports:
|
||||
- "8083:8080"
|
||||
whoami-ab:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-ab -certFile /certs/whoami-b.crt -keyFile /certs/whoami-b.key
|
||||
volumes:
|
||||
- ./fixtures/tcp:/certs
|
||||
|
||||
whoami-no-tls:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-no-tls
|
||||
ports:
|
||||
- "8084:8080"
|
||||
whoami-no-cert:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-no-cert
|
||||
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- "8085:80"
|
||||
whoami-no-tls:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-no-tls
|
||||
|
||||
whoami-banner:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-banner --banner
|
||||
ports:
|
||||
- "8086:8080"
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
||||
whoami-banner:
|
||||
image: traefik/whoamitcp
|
||||
command: -name whoami-banner --banner
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
timeoutEndpoint:
|
||||
image: yaman/timeout
|
||||
environment:
|
||||
- PROTO=http
|
||||
- PORT=9000
|
||||
ports:
|
||||
- "9000:9000"
|
||||
version: "3.8"
|
||||
services:
|
||||
timeoutEndpoint:
|
||||
image: yaman/timeout
|
||||
environment:
|
||||
PROTO: http
|
||||
PORT: 9000
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
whoami:
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.http.routers.route1.rule=PathPrefix(`/foo`)
|
||||
- traefik.http.routers.route1.middlewares=passtls
|
||||
- traefik.http.routers.route1.tls=true
|
||||
- traefik.http.middlewares.passtls.passtlsclientcert.pem=true
|
||||
traefik.http.routers.route1.rule: PathPrefix(`/foo`)
|
||||
traefik.http.routers.route1.middlewares: passtls
|
||||
traefik.http.routers.route1.tls: true
|
||||
traefik.http.middlewares.passtls.passtlsclientcert.pem: true
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
zipkin:
|
||||
image: openzipkin/zipkin:2.16.2
|
||||
environment:
|
||||
STORAGE_TYPE: mem
|
||||
JAVA_OPTS: -Dlogging.level.zipkin=DEBUG
|
||||
ports:
|
||||
- 9411:9411
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:1.14
|
||||
environment:
|
||||
COLLECTOR_ZIPKIN_HTTP_PORT: 9411
|
||||
ports:
|
||||
- "5775:5775/udp"
|
||||
- "6831:6831/udp"
|
||||
- "6832:6832/udp"
|
||||
- "5778:5778"
|
||||
- "16686:16686"
|
||||
- "14268:14268"
|
||||
- "9411:9411"
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
version: "3.8"
|
||||
services:
|
||||
zipkin:
|
||||
image: openzipkin/zipkin:2.16.2
|
||||
environment:
|
||||
STORAGE_TYPE: mem
|
||||
JAVA_OPTS: -Dlogging.level.zipkin=DEBUG
|
||||
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:1.14
|
||||
environment:
|
||||
COLLECTOR_ZIPKIN_HTTP_PORT: 9411
|
||||
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
whoami-a:
|
||||
image: traefik/whoamiudp:latest
|
||||
command: -name whoami-a
|
||||
version: "3.8"
|
||||
services:
|
||||
whoami-a:
|
||||
image: traefik/whoamiudp:latest
|
||||
command: -name whoami-a
|
||||
|
||||
whoami-b:
|
||||
image: traefik/whoamiudp:latest
|
||||
command: -name whoami-b
|
||||
whoami-b:
|
||||
image: traefik/whoamiudp:latest
|
||||
command: -name whoami-b
|
||||
|
||||
whoami-c:
|
||||
image: traefik/whoamiudp:latest
|
||||
command: -name whoami-c
|
||||
whoami-c:
|
||||
image: traefik/whoamiudp:latest
|
||||
command: -name whoami-c
|
||||
|
||||
whoami-d:
|
||||
image: traefik/whoami
|
||||
whoami-d:
|
||||
image: traefik/whoami
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,34 +1,41 @@
|
|||
noOverrideWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt1.rule=Host("no.override.whitelist.docker.local")
|
||||
- traefik.http.routers.rt1.middlewares=wl1
|
||||
- traefik.http.middlewares.wl1.ipwhiteList.sourceRange=8.8.8.8
|
||||
version: "3.8"
|
||||
services:
|
||||
noOverrideWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt1.rule: Host(`no.override.whitelist.docker.local`)
|
||||
traefik.http.routers.rt1.middlewares: wl1
|
||||
traefik.http.middlewares.wl1.ipwhiteList.sourceRange: 8.8.8.8
|
||||
|
||||
overrideIPStrategyRemoteAddrWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt2.rule=Host("override.remoteaddr.whitelist.docker.local")
|
||||
- traefik.http.routers.rt2.middlewares=wl2
|
||||
- traefik.http.middlewares.wl2.ipwhitelist.sourceRange=8.8.8.8
|
||||
- traefik.http.middlewares.wl2.ipwhitelist.ipStrategy=true
|
||||
overrideIPStrategyRemoteAddrWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt2.rule: Host(`override.remoteaddr.whitelist.docker.local`)
|
||||
traefik.http.routers.rt2.middlewares: wl2
|
||||
traefik.http.middlewares.wl2.ipwhitelist.sourceRange: 8.8.8.8
|
||||
traefik.http.middlewares.wl2.ipwhitelist.ipStrategy: true
|
||||
|
||||
overrideIPStrategyDepthWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt3.rule=Host("override.depth.whitelist.docker.local")
|
||||
- traefik.http.routers.rt3.middlewares=wl3
|
||||
- traefik.http.middlewares.wl3.ipwhitelist.sourceRange=8.8.8.8
|
||||
- traefik.http.middlewares.wl3.ipwhitelist.ipStrategy.depth=3
|
||||
overrideIPStrategyDepthWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt3.rule: Host(`override.depth.whitelist.docker.local`)
|
||||
traefik.http.routers.rt3.middlewares: wl3
|
||||
traefik.http.middlewares.wl3.ipwhitelist.sourceRange: 8.8.8.8
|
||||
traefik.http.middlewares.wl3.ipwhitelist.ipStrategy.depth: 3
|
||||
|
||||
overrideIPStrategyExcludedIPsWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.rt4.rule=Host("override.excludedips.whitelist.docker.local")
|
||||
- traefik.http.routers.rt4.middlewares=wl4
|
||||
- traefik.http.middlewares.wl4.ipwhitelist.sourceRange=8.8.8.8
|
||||
- traefik.http.middlewares.wl4.ipwhitelist.ipStrategy.excludedIPs=10.0.0.1,10.0.0.2
|
||||
overrideIPStrategyExcludedIPsWhitelist:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.rt4.rule: Host(`override.excludedips.whitelist.docker.local`)
|
||||
traefik.http.routers.rt4.middlewares: wl4
|
||||
traefik.http.middlewares.wl4.ipwhitelist.sourceRange: 8.8.8.8
|
||||
traefik.http.middlewares.wl4.ipwhitelist.ipStrategy.excludedIPs: 10.0.0.1,10.0.0.2
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
zookeeper:
|
||||
image: zookeeper:3.5
|
||||
ports:
|
||||
- "2181:2181"
|
||||
version: "3.8"
|
||||
services:
|
||||
zookeeper:
|
||||
image: zookeeper:3.5
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: traefik-test-network
|
||||
external: true
|
||||
|
|
|
@ -23,8 +23,8 @@ frontend TestServerTestV2
|
|||
|
||||
backend TestServerNodes
|
||||
mode tcp
|
||||
server TestServer01 172.17.0.1:8000 send-proxy
|
||||
server TestServer01 traefik:8000 send-proxy
|
||||
|
||||
backend TestServerNodesV2
|
||||
mode tcp
|
||||
server TestServer01 172.17.0.1:8000 send-proxy-v2
|
||||
server TestServer01 traefik:8000 send-proxy-v2
|
||||
|
|
|
@ -3,6 +3,7 @@ package integration
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -14,12 +15,16 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
type RestSuite struct{ BaseSuite }
|
||||
type RestSuite struct {
|
||||
BaseSuite
|
||||
whoamiAddr string
|
||||
}
|
||||
|
||||
func (s *RestSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "rest")
|
||||
s.composeUp(c)
|
||||
|
||||
s.composeProject.Start(c)
|
||||
s.whoamiAddr = net.JoinHostPort(s.getComposeServiceIP(c, "whoami1"), "80")
|
||||
}
|
||||
|
||||
func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
|
||||
|
@ -60,7 +65,7 @@ func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
|
|||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
||||
URL: "http://" + s.whoamiAddr,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -86,7 +91,7 @@ func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
|
|||
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
||||
Address: s.whoamiAddr,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -164,7 +169,7 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
|
|||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
||||
URL: "http://" + s.whoamiAddr,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -190,7 +195,7 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
|
|||
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
||||
Address: s.whoamiAddr,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -213,10 +218,10 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains(test.ruleMatch))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains(test.ruleMatch))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||
err = try.GetRequest("http://127.0.0.1:8000/", time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,18 +11,20 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
type RetrySuite struct{ BaseSuite }
|
||||
type RetrySuite struct {
|
||||
BaseSuite
|
||||
whoamiIP string
|
||||
}
|
||||
|
||||
func (s *RetrySuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "retry")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
s.whoamiIP = s.getComposeServiceIP(c, "whoami")
|
||||
}
|
||||
|
||||
func (s *RetrySuite) TestRetry(c *check.C) {
|
||||
whoamiEndpoint := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct {
|
||||
WhoamiEndpoint string
|
||||
}{whoamiEndpoint})
|
||||
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct{ WhoamiIP string }{s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -44,10 +46,7 @@ func (s *RetrySuite) TestRetry(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *RetrySuite) TestRetryBackoff(c *check.C) {
|
||||
whoamiEndpoint := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
file := s.adaptFile(c, "fixtures/retry/backoff.toml", struct {
|
||||
WhoamiEndpoint string
|
||||
}{whoamiEndpoint})
|
||||
file := s.adaptFile(c, "fixtures/retry/backoff.toml", struct{ WhoamiIP string }{s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -72,10 +71,7 @@ func (s *RetrySuite) TestRetryBackoff(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *RetrySuite) TestRetryWebsocket(c *check.C) {
|
||||
whoamiEndpoint := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct {
|
||||
WhoamiEndpoint string
|
||||
}{whoamiEndpoint})
|
||||
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct{ WhoamiIP string }{s.whoamiIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
|
@ -50,7 +51,6 @@ func (s *SimpleSuite) TestSimpleDefaultConfig(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
// TODO validate : run on 80
|
||||
// Expected a 404 as we did not configure anything
|
||||
err = try.GetRequest("http://127.0.0.1:8000/", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -93,17 +93,20 @@ func (s *SimpleSuite) TestPrintHelp(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestRequestAcceptGraceTimeout(c *check.C) {
|
||||
s.createComposeProject(c, "reqacceptgrace")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
whoami := "http://" + s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress + ":80"
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
whoamiURL := "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "whoami"), "80")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/reqacceptgrace.toml", struct {
|
||||
Server string
|
||||
}{whoami})
|
||||
}{whoamiURL})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
@ -193,15 +196,17 @@ func (s *SimpleSuite) TestCustomPingTerminationStatusCode(c *check.C) {
|
|||
func (s *SimpleSuite) TestStatsWithMultipleEntryPoint(c *check.C) {
|
||||
c.Skip("Stats is missing")
|
||||
s.createComposeProject(c, "stats")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
whoami1 := "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80"
|
||||
whoami2 := "http://" + s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress + ":80"
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
whoami1URL := "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "whoami1"), "80")
|
||||
whoami2URL := "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "whoami2"), "80")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/simple_stats.toml", struct {
|
||||
Server1 string
|
||||
Server2 string
|
||||
}{whoami1, whoami2})
|
||||
}{whoami1URL, whoami2URL})
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
defer output(c)
|
||||
|
||||
|
@ -229,7 +234,9 @@ func (s *SimpleSuite) TestNoAuthOnPing(c *check.C) {
|
|||
c.Skip("Waiting for new api handler implementation")
|
||||
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
file := s.adaptFile(c, "./fixtures/simple_auth.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
|
@ -249,7 +256,9 @@ func (s *SimpleSuite) TestNoAuthOnPing(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestDefaultEntryPointHTTP(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--log.level=DEBUG", "--providers.docker", "--api.insecure")
|
||||
defer output(c)
|
||||
|
@ -267,7 +276,9 @@ func (s *SimpleSuite) TestDefaultEntryPointHTTP(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestWithNonExistingEntryPoint(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--log.level=DEBUG", "--providers.docker", "--api.insecure")
|
||||
defer output(c)
|
||||
|
@ -285,7 +296,9 @@ func (s *SimpleSuite) TestWithNonExistingEntryPoint(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestMetricsPrometheusDefaultEntryPoint(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.insecure", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--metrics.prometheus.addrouterslabels=true", "--log.level=DEBUG")
|
||||
defer output(c)
|
||||
|
@ -315,7 +328,9 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntryPoint(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestMetricsPrometheusTwoRoutersOneService(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.insecure", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--metrics.prometheus.addentrypointslabels=false", "--metrics.prometheus.addrouterslabels=true", "--log.level=DEBUG")
|
||||
defer output(c)
|
||||
|
@ -346,22 +361,22 @@ func (s *SimpleSuite) TestMetricsPrometheusTwoRoutersOneService(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Reqs count of 1 for both routers
|
||||
c.Assert(string(body), checker.Contains, "traefik_router_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",router=\"router1@docker\",service=\"whoami1-integrationtestbase@docker\"} 1")
|
||||
c.Assert(string(body), checker.Contains, "traefik_router_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",router=\"router2@docker\",service=\"whoami1-integrationtestbase@docker\"} 1")
|
||||
c.Assert(string(body), checker.Contains, "traefik_router_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",router=\"router1@docker\",service=\"whoami1-traefik-integration-test-base@docker\"} 1")
|
||||
c.Assert(string(body), checker.Contains, "traefik_router_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",router=\"router2@docker\",service=\"whoami1-traefik-integration-test-base@docker\"} 1")
|
||||
// Reqs count of 2 for service behind both routers
|
||||
c.Assert(string(body), checker.Contains, "traefik_service_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",service=\"whoami1-integrationtestbase@docker\"} 2")
|
||||
c.Assert(string(body), checker.Contains, "traefik_service_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",service=\"whoami1-traefik-integration-test-base@docker\"} 2")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
ipWhoami01 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
ipWhoami02 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
file := s.adaptFile(c, "fixtures/multiple_provider.toml", struct{ IP string }{
|
||||
IP: ipWhoami02,
|
||||
})
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
whoami1IP := s.getComposeServiceIP(c, "whoami1")
|
||||
whoami2IP := s.getComposeServiceIP(c, "whoami2")
|
||||
file := s.adaptFile(c, "fixtures/multiple_provider.toml", struct{ IP string }{IP: whoami2IP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -374,16 +389,18 @@ func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.BodyContains(ipWhoami01))
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.BodyContains(whoami1IP))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/file", 1*time.Second, try.BodyContains(ipWhoami02))
|
||||
err = try.GetRequest("http://127.0.0.1:8000/file", 1*time.Second, try.BodyContains(whoami2IP))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestIPStrategyWhitelist(c *check.C) {
|
||||
s.createComposeProject(c, "whitelist")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile("fixtures/simple_whitelist.toml"))
|
||||
defer output(c)
|
||||
|
@ -451,7 +468,9 @@ func (s *SimpleSuite) TestIPStrategyWhitelist(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestXForwardedHeaders(c *check.C) {
|
||||
s.createComposeProject(c, "whitelist")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile("fixtures/simple_whitelist.toml"))
|
||||
defer output(c)
|
||||
|
@ -479,13 +498,13 @@ func (s *SimpleSuite) TestXForwardedHeaders(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestMultiProvider(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
server := "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
file := s.adaptFile(c, "fixtures/multiprovider.toml", struct {
|
||||
Server string
|
||||
}{Server: server})
|
||||
whoamiURL := "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "whoami1"), "80")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/multiprovider.toml", struct{ Server string }{Server: whoamiURL})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -530,13 +549,13 @@ func (s *SimpleSuite) TestMultiProvider(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestSimpleConfigurationHostRequestTrailingPeriod(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
server := "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
file := s.adaptFile(c, "fixtures/file/simple-hosts.toml", struct {
|
||||
Server string
|
||||
}{Server: server})
|
||||
whoamiURL := "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "whoami1"), "80")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/file/simple-hosts.toml", struct{ Server string }{Server: whoamiURL})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -707,15 +726,17 @@ func (s *SimpleSuite) TestUDPServiceConfigErrors(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestWRR(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
server1 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
server2 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
whoami1IP := s.getComposeServiceIP(c, "whoami1")
|
||||
whoami2IP := s.getComposeServiceIP(c, "whoami2")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/wrr.toml", struct {
|
||||
Server1 string
|
||||
Server2 string
|
||||
}{Server1: "http://" + server1, Server2: "http://" + server2})
|
||||
}{Server1: "http://" + whoami1IP, Server2: "http://" + whoami2IP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -740,29 +761,31 @@ func (s *SimpleSuite) TestWRR(c *check.C) {
|
|||
body, err := io.ReadAll(response.Body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if strings.Contains(string(body), server1) {
|
||||
repartition[server1]++
|
||||
if strings.Contains(string(body), whoami1IP) {
|
||||
repartition[whoami1IP]++
|
||||
}
|
||||
if strings.Contains(string(body), server2) {
|
||||
repartition[server2]++
|
||||
if strings.Contains(string(body), whoami2IP) {
|
||||
repartition[whoami2IP]++
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(repartition[server1], checker.Equals, 3)
|
||||
c.Assert(repartition[server2], checker.Equals, 1)
|
||||
c.Assert(repartition[whoami1IP], checker.Equals, 3)
|
||||
c.Assert(repartition[whoami2IP], checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestWRRSticky(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
server1 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
server2 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
whoami1IP := s.getComposeServiceIP(c, "whoami1")
|
||||
whoami2IP := s.getComposeServiceIP(c, "whoami2")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/wrr_sticky.toml", struct {
|
||||
Server1 string
|
||||
Server2 string
|
||||
}{Server1: "http://" + server1, Server2: "http://" + server2})
|
||||
}{Server1: "http://" + whoami1IP, Server2: "http://" + whoami2IP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -791,16 +814,16 @@ func (s *SimpleSuite) TestWRRSticky(c *check.C) {
|
|||
body, err := io.ReadAll(response.Body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if strings.Contains(string(body), server1) {
|
||||
repartition[server1]++
|
||||
if strings.Contains(string(body), whoami1IP) {
|
||||
repartition[whoami1IP]++
|
||||
}
|
||||
if strings.Contains(string(body), server2) {
|
||||
repartition[server2]++
|
||||
if strings.Contains(string(body), whoami2IP) {
|
||||
repartition[whoami2IP]++
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(repartition[server1], checker.Equals, 4)
|
||||
c.Assert(repartition[server2], checker.Equals, 0)
|
||||
c.Assert(repartition[whoami1IP], checker.Equals, 4)
|
||||
c.Assert(repartition[whoami2IP], checker.Equals, 0)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestMirror(c *check.C) {
|
||||
|
@ -1037,7 +1060,9 @@ func (s *SimpleSuite) TestMirrorCanceled(c *check.C) {
|
|||
|
||||
func (s *SimpleSuite) TestSecureAPI(c *check.C) {
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
s.composeUp(c)
|
||||
defer s.composeDown(c)
|
||||
|
||||
file := s.adaptFile(c, "./fixtures/simple_secure_api.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
|
|
|
@ -2,6 +2,9 @@ package integration
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
@ -18,7 +21,7 @@ type TCPSuite struct{ BaseSuite }
|
|||
|
||||
func (s *TCPSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "tcp")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *TCPSuite) TestMixed(c *check.C) {
|
||||
|
@ -36,12 +39,12 @@ func (s *TCPSuite) TestMixed(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Traefik passes through, termination handled by whoami-a
|
||||
out, err := guessWho("127.0.0.1:8093", "whoami-a.test", true)
|
||||
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "whoami-a")
|
||||
|
||||
// Traefik passes through, termination handled by whoami-b
|
||||
out, err = guessWho("127.0.0.1:8093", "whoami-b.test", true)
|
||||
out, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "whoami-b")
|
||||
|
||||
|
@ -116,12 +119,12 @@ func (s *TCPSuite) TestNonTLSFallback(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Traefik passes through, termination handled by whoami-a
|
||||
out, err := guessWho("127.0.0.1:8093", "whoami-a.test", true)
|
||||
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "whoami-a")
|
||||
|
||||
// Traefik passes through, termination handled by whoami-b
|
||||
out, err = guessWho("127.0.0.1:8093", "whoami-b.test", true)
|
||||
out, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "whoami-b")
|
||||
|
||||
|
@ -211,19 +214,52 @@ func (s *TCPSuite) TestMiddlewareWhiteList(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 50*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-a.test`)"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-a.test`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Traefik not passes through, ipWhitelist closes connection
|
||||
_, err = guessWho("127.0.0.1:8093", "whoami-a.test", true)
|
||||
c.Assert(err, checker.NotNil)
|
||||
_, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
|
||||
c.Assert(err, checker.ErrorMatches, "EOF")
|
||||
|
||||
// Traefik passes through, termination handled by whoami-b
|
||||
out, err := guessWho("127.0.0.1:8093", "whoami-b.test", true)
|
||||
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "whoami-b")
|
||||
}
|
||||
|
||||
func (s *TCPSuite) TestWRR(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/tcp/wrr.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-b.test`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
call := map[string]int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
// Traefik passes through, termination handled by whoami-b or whoami-bb
|
||||
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
switch {
|
||||
case strings.Contains(out, "whoami-b"):
|
||||
call["whoami-b"]++
|
||||
case strings.Contains(out, "whoami-ab"):
|
||||
call["whoami-ab"]++
|
||||
default:
|
||||
call["unknown"]++
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
c.Assert(call, checker.DeepEquals, map[string]int{"whoami-b": 3, "whoami-ab": 1})
|
||||
}
|
||||
|
||||
func welcome(addr string) (string, error) {
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||
if err != nil {
|
||||
|
@ -291,34 +327,54 @@ func guessWhoTLSMaxVersion(addr, serverName string, tlsCall bool, tlsMaxVersion
|
|||
return string(out[:n]), nil
|
||||
}
|
||||
|
||||
func (s *TCPSuite) TestWRR(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/tcp/wrr.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
// guessWhoTLSPassthrough guesses service identity and ensures that the
|
||||
// certificate is valid for the given server name.
|
||||
func guessWhoTLSPassthrough(addr, serverName string) (string, error) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
conn, err = tls.Dial("tcp", addr, &tls.Config{
|
||||
ServerName: serverName,
|
||||
InsecureSkipVerify: true,
|
||||
MinVersion: 0,
|
||||
MaxVersion: 0,
|
||||
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
if len(rawCerts) > 1 {
|
||||
return errors.New("tls: more than one certificates from peer")
|
||||
}
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
cert, err := x509.ParseCertificate(rawCerts[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("tls: failed to parse certificate from peer: %w", err)
|
||||
}
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
if cert.Subject.CommonName == serverName {
|
||||
return nil
|
||||
}
|
||||
|
||||
call := map[string]int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
// Traefik passes through, termination handled by whoami-a
|
||||
out, err := guessWho("127.0.0.1:8093", "whoami-a.test", true)
|
||||
c.Assert(err, checker.IsNil)
|
||||
switch {
|
||||
case strings.Contains(out, "whoami-a"):
|
||||
call["whoami-a"]++
|
||||
case strings.Contains(out, "whoami-b"):
|
||||
call["whoami-b"]++
|
||||
default:
|
||||
call["unknown"]++
|
||||
}
|
||||
if err = cert.VerifyHostname(serverName); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("tls: no valid certificate for serverName %s", serverName)
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
_, err = conn.Write([]byte("WHO"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
c.Assert(call, checker.DeepEquals, map[string]int{"whoami-a": 3, "whoami-b": 1})
|
||||
out := make([]byte, 2048)
|
||||
n, err := conn.Read(out)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(out[:n]), nil
|
||||
}
|
||||
|
|
|
@ -15,14 +15,12 @@ type TimeoutSuite struct{ BaseSuite }
|
|||
|
||||
func (s *TimeoutSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "timeout")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *TimeoutSuite) TestForwardingTimeouts(c *check.C) {
|
||||
httpTimeoutEndpoint := s.composeProject.Container(c, "timeoutEndpoint").NetworkSettings.IPAddress
|
||||
file := s.adaptFile(c, "fixtures/timeout/forwarding_timeouts.toml", struct {
|
||||
TimeoutEndpoint string
|
||||
}{httpTimeoutEndpoint})
|
||||
timeoutEndpointIP := s.getComposeServiceIP(c, "timeoutEndpoint")
|
||||
file := s.adaptFile(c, "fixtures/timeout/forwarding_timeouts.toml", struct{ TimeoutEndpoint string }{timeoutEndpointIP})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
|
@ -40,7 +38,7 @@ func (s *TimeoutSuite) TestForwardingTimeouts(c *check.C) {
|
|||
c.Assert(response.StatusCode, checker.Equals, http.StatusGatewayTimeout)
|
||||
|
||||
// Check that timeout service is available
|
||||
statusURL := fmt.Sprintf("http://%s:9000/statusTest?status=200", httpTimeoutEndpoint)
|
||||
statusURL := fmt.Sprintf("http://%s:9000/statusTest?status=200", timeoutEndpointIP)
|
||||
c.Assert(try.GetRequest(statusURL, 60*time.Second, try.StatusCodeIs(http.StatusOK)), checker.IsNil)
|
||||
|
||||
// This simulates a ResponseHeaderTimeout.
|
||||
|
|
|
@ -21,7 +21,7 @@ type TLSClientHeadersSuite struct{ BaseSuite }
|
|||
|
||||
func (s *TLSClientHeadersSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "tlsclientheaders")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
|
||||
|
|
|
@ -12,47 +12,49 @@ import (
|
|||
|
||||
type TracingSuite struct {
|
||||
BaseSuite
|
||||
WhoAmiIP string
|
||||
WhoAmiPort int
|
||||
IP string
|
||||
whoamiIP string
|
||||
whoamiPort int
|
||||
tracerIP string
|
||||
}
|
||||
|
||||
type TracingTemplate struct {
|
||||
WhoAmiIP string
|
||||
WhoAmiPort int
|
||||
WhoamiIP string
|
||||
WhoamiPort int
|
||||
IP string
|
||||
TraceContextHeaderName string
|
||||
}
|
||||
|
||||
func (s *TracingSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "tracing")
|
||||
s.composeProject.Start(c, "whoami")
|
||||
s.composeUp(c)
|
||||
|
||||
s.WhoAmiIP = s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
|
||||
s.WhoAmiPort = 80
|
||||
s.whoamiIP = s.getComposeServiceIP(c, "whoami")
|
||||
s.whoamiPort = 80
|
||||
}
|
||||
|
||||
func (s *TracingSuite) startZipkin(c *check.C) {
|
||||
s.composeProject.Start(c, "zipkin")
|
||||
s.IP = s.composeProject.Container(c, "zipkin").NetworkSettings.IPAddress
|
||||
s.composeUp(c, "zipkin")
|
||||
s.tracerIP = s.getComposeServiceIP(c, "zipkin")
|
||||
|
||||
// Wait for Zipkin to turn ready.
|
||||
err := try.GetRequest("http://"+s.IP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
err := try.GetRequest("http://"+s.tracerIP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestZipkinRateLimit(c *check.C) {
|
||||
s.startZipkin(c)
|
||||
defer s.composeProject.Stop(c, "zipkin")
|
||||
// defer s.composeStop(c, "zipkin")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: s.WhoAmiPort,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.tracerIP,
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer s.killCmd(cmd)
|
||||
|
@ -87,17 +89,18 @@ func (s *TracingSuite) TestZipkinRateLimit(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestZipkinRetry(c *check.C) {
|
||||
s.startZipkin(c)
|
||||
defer s.composeProject.Stop(c, "zipkin")
|
||||
defer s.composeStop(c, "zipkin")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: 81,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: 81,
|
||||
IP: s.tracerIP,
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
||||
|
@ -114,17 +117,18 @@ func (s *TracingSuite) TestZipkinRetry(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestZipkinAuth(c *check.C) {
|
||||
s.startZipkin(c)
|
||||
defer s.composeProject.Stop(c, "zipkin")
|
||||
defer s.composeStop(c, "zipkin")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: s.WhoAmiPort,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.tracerIP,
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
||||
|
@ -141,26 +145,27 @@ func (s *TracingSuite) TestZipkinAuth(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint web", "basic-auth@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint web", "basic-auth@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) startJaeger(c *check.C) {
|
||||
s.composeProject.Start(c, "jaeger")
|
||||
s.IP = s.composeProject.Container(c, "jaeger").NetworkSettings.IPAddress
|
||||
s.composeUp(c, "jaeger", "whoami")
|
||||
s.tracerIP = s.getComposeServiceIP(c, "jaeger")
|
||||
|
||||
// Wait for Jaeger to turn ready.
|
||||
err := try.GetRequest("http://"+s.IP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
err := try.GetRequest("http://"+s.tracerIP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerRateLimit(c *check.C) {
|
||||
s.startJaeger(c)
|
||||
defer s.composeProject.Stop(c, "jaeger")
|
||||
defer s.composeStop(c, "jaeger")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: s.WhoAmiPort,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.tracerIP,
|
||||
TraceContextHeaderName: "uber-trace-id",
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
@ -200,17 +205,18 @@ func (s *TracingSuite) TestJaegerRateLimit(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerRetry(c *check.C) {
|
||||
s.startJaeger(c)
|
||||
defer s.composeProject.Stop(c, "jaeger")
|
||||
defer s.composeStop(c, "jaeger")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: 81,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: 81,
|
||||
IP: s.tracerIP,
|
||||
TraceContextHeaderName: "uber-trace-id",
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
@ -228,17 +234,18 @@ func (s *TracingSuite) TestJaegerRetry(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerAuth(c *check.C) {
|
||||
s.startJaeger(c)
|
||||
defer s.composeProject.Stop(c, "jaeger")
|
||||
defer s.composeStop(c, "jaeger")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: s.WhoAmiPort,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.tracerIP,
|
||||
TraceContextHeaderName: "uber-trace-id",
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
@ -256,17 +263,18 @@ func (s *TracingSuite) TestJaegerAuth(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerCustomHeader(c *check.C) {
|
||||
s.startJaeger(c)
|
||||
defer s.composeProject.Stop(c, "jaeger")
|
||||
defer s.composeStop(c, "jaeger")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: s.WhoAmiPort,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.tracerIP,
|
||||
TraceContextHeaderName: "powpow",
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
@ -284,17 +292,18 @@ func (s *TracingSuite) TestJaegerCustomHeader(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerAuthCollector(c *check.C) {
|
||||
s.startJaeger(c)
|
||||
defer s.composeProject.Stop(c, "jaeger")
|
||||
defer s.composeStop(c, "jaeger")
|
||||
|
||||
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger-collector.toml", TracingTemplate{
|
||||
WhoAmiIP: s.WhoAmiIP,
|
||||
WhoAmiPort: s.WhoAmiPort,
|
||||
IP: s.IP,
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.tracerIP,
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
||||
|
@ -311,6 +320,6 @@ func (s *TracingSuite) TestJaegerAuthCollector(c *check.C) {
|
|||
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://"+s.IP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ type UDPSuite struct{ BaseSuite }
|
|||
|
||||
func (s *UDPSuite) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "udp")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
}
|
||||
|
||||
func guessWhoUDP(addr string) (string, error) {
|
||||
|
@ -47,21 +47,16 @@ func guessWhoUDP(addr string) (string, error) {
|
|||
}
|
||||
|
||||
func (s *UDPSuite) TestWRR(c *check.C) {
|
||||
whoamiAIP := s.composeProject.Container(c, "whoami-a").NetworkSettings.IPAddress
|
||||
whoamiBIP := s.composeProject.Container(c, "whoami-b").NetworkSettings.IPAddress
|
||||
whoamiCIP := s.composeProject.Container(c, "whoami-c").NetworkSettings.IPAddress
|
||||
whoamiDIP := s.composeProject.Container(c, "whoami-d").NetworkSettings.IPAddress
|
||||
|
||||
file := s.adaptFile(c, "fixtures/udp/wrr.toml", struct {
|
||||
WhoamiAIP string
|
||||
WhoamiBIP string
|
||||
WhoamiCIP string
|
||||
WhoamiDIP string
|
||||
}{
|
||||
WhoamiAIP: whoamiAIP,
|
||||
WhoamiBIP: whoamiBIP,
|
||||
WhoamiCIP: whoamiCIP,
|
||||
WhoamiDIP: whoamiDIP,
|
||||
WhoamiAIP: s.getComposeServiceIP(c, "whoami-a"),
|
||||
WhoamiBIP: s.getComposeServiceIP(c, "whoami-b"),
|
||||
WhoamiCIP: s.getComposeServiceIP(c, "whoami-c"),
|
||||
WhoamiDIP: s.getComposeServiceIP(c, "whoami-d"),
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package integration
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -18,20 +19,25 @@ import (
|
|||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Zk test suites (using libcompose).
|
||||
// Zk test suites.
|
||||
type ZookeeperSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
kvClient store.Store
|
||||
zookeeperAddr string
|
||||
}
|
||||
|
||||
func (s *ZookeeperSuite) setupStore(c *check.C) {
|
||||
s.createComposeProject(c, "zookeeper")
|
||||
s.composeProject.Start(c)
|
||||
s.composeUp(c)
|
||||
|
||||
zookeeper.Register()
|
||||
kv, err := valkeyrie.NewStore(
|
||||
|
||||
s.zookeeperAddr = net.JoinHostPort(s.getComposeServiceIP(c, "zookeeper"), "2181")
|
||||
|
||||
var err error
|
||||
s.kvClient, err = valkeyrie.NewStore(
|
||||
store.ZK,
|
||||
[]string{s.composeProject.Container(c, "zookeeper").NetworkSettings.IPAddress + ":2181"},
|
||||
[]string{s.zookeeperAddr},
|
||||
&store.Config{
|
||||
ConnectionTimeout: 10 * time.Second,
|
||||
},
|
||||
|
@ -39,27 +45,16 @@ func (s *ZookeeperSuite) setupStore(c *check.C) {
|
|||
if err != nil {
|
||||
c.Fatal("Cannot create store zookeeper")
|
||||
}
|
||||
s.kvClient = kv
|
||||
|
||||
// wait for zk
|
||||
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
|
||||
err = try.Do(60*time.Second, try.KVExists(s.kvClient, "test"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ZookeeperSuite) TearDownTest(c *check.C) {
|
||||
// shutdown and delete compose project
|
||||
if s.composeProject != nil {
|
||||
s.composeProject.Stop(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ZookeeperSuite) TearDownSuite(c *check.C) {}
|
||||
|
||||
func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
|
||||
s.setupStore(c)
|
||||
|
||||
address := s.composeProject.Container(c, "zookeeper").NetworkSettings.IPAddress + ":2181"
|
||||
file := s.adaptFile(c, "fixtures/zookeeper/simple.toml", struct{ ZkAddress string }{address})
|
||||
file := s.adaptFile(c, "fixtures/zookeeper/simple.toml", struct{ ZkAddress string }{s.zookeeperAddr})
|
||||
defer os.Remove(file)
|
||||
|
||||
data := map[string]string{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# This file is not meant as a usable Traefik configuration.
|
||||
# It is only used in tests as a sample for serialization.
|
||||
[global]
|
||||
checkNewVersion = true
|
||||
sendAnonymousUsage = true
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/traefik/yaegi/interp"
|
||||
"github.com/traefik/yaegi/stdlib"
|
||||
|
@ -46,7 +47,7 @@ func NewBuilder(client *Client, plugins map[string]Descriptor, localPlugins map[
|
|||
return nil, fmt.Errorf("%s: failed to read manifest: %w", desc.ModuleName, err)
|
||||
}
|
||||
|
||||
i := interp.New(interp.Options{GoPath: client.GoPath()})
|
||||
i := interp.New(interp.Options{GoPath: client.GoPath(), Env: os.Environ()})
|
||||
|
||||
err = i.Use(stdlib.Symbols)
|
||||
if err != nil {
|
||||
|
@ -89,7 +90,7 @@ func NewBuilder(client *Client, plugins map[string]Descriptor, localPlugins map[
|
|||
return nil, fmt.Errorf("%s: failed to read manifest: %w", desc.ModuleName, err)
|
||||
}
|
||||
|
||||
i := interp.New(interp.Options{GoPath: localGoPath})
|
||||
i := interp.New(interp.Options{GoPath: localGoPath, Env: os.Environ()})
|
||||
|
||||
err = i.Use(stdlib.Symbols)
|
||||
if err != nil {
|
||||
|
|
|
@ -9,6 +9,24 @@ spec:
|
|||
prefixes:
|
||||
- /tobestripped
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: ratelimit
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
rateLimit:
|
||||
period: 1m
|
||||
average: 6
|
||||
burst: 12
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
excludedIPs:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
|
@ -40,5 +58,6 @@ spec:
|
|||
port: 80
|
||||
middlewares:
|
||||
- name: stripprefix
|
||||
- name: ratelimit
|
||||
- name: addprefix
|
||||
namespace: foo
|
||||
|
|
|
@ -443,6 +443,10 @@ func createRateLimitMiddleware(rateLimit *v1alpha1.RateLimit) (*dynamic.RateLimi
|
|||
}
|
||||
}
|
||||
|
||||
if rateLimit.SourceCriterion != nil {
|
||||
rl.SourceCriterion = rateLimit.SourceCriterion
|
||||
}
|
||||
|
||||
return rl, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1472,10 +1472,22 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Service: "default-test2-route-23c7f4c450289ee29016",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)",
|
||||
Priority: 12,
|
||||
Middlewares: []string{"default-stripprefix", "foo-addprefix"},
|
||||
Middlewares: []string{"default-stripprefix", "default-ratelimit", "foo-addprefix"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ratelimit": {
|
||||
RateLimit: &dynamic.RateLimit{
|
||||
Average: 6,
|
||||
Burst: 12,
|
||||
Period: ptypes.Duration(60 * time.Second),
|
||||
SourceCriterion: &dynamic.SourceCriterion{
|
||||
IPStrategy: &dynamic.IPStrategy{
|
||||
ExcludedIPs: []string{"127.0.0.1/32", "192.168.1.7"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-stripprefix": {
|
||||
StripPrefix: &dynamic.StripPrefix{
|
||||
Prefixes: []string{"/tobestripped"},
|
||||
|
|
|
@ -8,7 +8,8 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const receiveMTU = 8192
|
||||
// maxDatagramSize is the maximum size of a UDP datagram.
|
||||
const maxDatagramSize = 65535
|
||||
|
||||
const closeRetryInterval = 500 * time.Millisecond
|
||||
|
||||
|
@ -135,7 +136,8 @@ func (l *Listener) readLoop() {
|
|||
// Allocating a new buffer for every read avoids
|
||||
// overwriting data in c.msgs in case the next packet is received
|
||||
// before c.msgs is emptied via Read()
|
||||
buf := make([]byte, receiveMTU)
|
||||
buf := make([]byte, maxDatagramSize)
|
||||
|
||||
n, raddr, err := l.pConn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -144,6 +146,7 @@ func (l *Listener) readLoop() {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case conn.receiveCh <- buf[:n]:
|
||||
case <-conn.doneCh:
|
||||
|
@ -249,7 +252,9 @@ func (c *Conn) readLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
// Read implements io.Reader for a Conn.
|
||||
// Read reads up to len(p) bytes into p from the connection.
|
||||
// Each call corresponds to at most one datagram.
|
||||
// If p is smaller than the datagram, the extra bytes will be discarded.
|
||||
func (c *Conn) Read(p []byte) (int, error) {
|
||||
select {
|
||||
case c.readCh <- p:
|
||||
|
@ -258,22 +263,21 @@ func (c *Conn) Read(p []byte) (int, error) {
|
|||
c.lastActivity = time.Now()
|
||||
c.muActivity.Unlock()
|
||||
return n, nil
|
||||
|
||||
case <-c.doneCh:
|
||||
return 0, io.EOF
|
||||
}
|
||||
}
|
||||
|
||||
// Write implements io.Writer for a Conn.
|
||||
// Write writes len(p) bytes from p to the underlying connection.
|
||||
// Each call sends at most one datagram.
|
||||
// It is an error to send a message larger than the system's max UDP datagram size.
|
||||
func (c *Conn) Write(p []byte) (n int, err error) {
|
||||
l := c.listener
|
||||
if l == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
c.muActivity.Lock()
|
||||
c.lastActivity = time.Now()
|
||||
c.muActivity.Unlock()
|
||||
return l.pConn.WriteTo(p, c.rAddr)
|
||||
|
||||
return c.listener.pConn.WriteTo(p, c.rAddr)
|
||||
}
|
||||
|
||||
func (c *Conn) close() {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package udp
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -317,6 +319,61 @@ func TestShutdown(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReadLoopMaxDataSize(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
// sudo sysctl -w net.inet.udp.maxdgram=65507
|
||||
t.Skip("Skip test on darwin as the maximum dgram size is set to 9216 bytes by default")
|
||||
}
|
||||
|
||||
// Theoretical maximum size of data in a UDP datagram.
|
||||
// 65535 − 8 (UDP header) − 20 (IP header).
|
||||
dataSize := 65507
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
addr, err := net.ResolveUDPAddr("udp", ":0")
|
||||
require.NoError(t, err)
|
||||
|
||||
l, err := Listen("udp", addr, 3*time.Second)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err := l.Close()
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
conn, err := l.Accept()
|
||||
require.NoError(t, err)
|
||||
|
||||
buffer := make([]byte, dataSize)
|
||||
|
||||
n, err := conn.Read(buffer)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, dataSize, n)
|
||||
}()
|
||||
|
||||
c, err := net.Dial("udp", l.Addr().String())
|
||||
require.NoError(t, err)
|
||||
|
||||
data := make([]byte, dataSize)
|
||||
|
||||
_, err = rand.Read(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = c.Write(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-doneCh:
|
||||
case <-time.Tick(5 * time.Second):
|
||||
t.Fatal("Timeout waiting for datagram read")
|
||||
}
|
||||
}
|
||||
|
||||
// requireEcho tests that the conn session is live and functional,
|
||||
// by writing data through it, and expecting the same data as a response when reading on it.
|
||||
// It fatals if the read blocks longer than timeout,
|
||||
|
|
|
@ -20,14 +20,14 @@ func NewProxy(address string) (*Proxy, error) {
|
|||
|
||||
// ServeUDP implements the Handler interface.
|
||||
func (p *Proxy) ServeUDP(conn *Conn) {
|
||||
log.Debugf("Handling connection from %s", conn.rAddr)
|
||||
log.WithoutContext().Debugf("Handling connection from %s", conn.rAddr)
|
||||
|
||||
// needed because of e.g. server.trackedConnection
|
||||
defer conn.Close()
|
||||
|
||||
connBackend, err := net.Dial("udp", p.target)
|
||||
if err != nil {
|
||||
log.Errorf("Error while connecting to backend: %v", err)
|
||||
log.WithoutContext().Errorf("Error while connecting to backend: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ func (p *Proxy) ServeUDP(conn *Conn) {
|
|||
defer connBackend.Close()
|
||||
|
||||
errChan := make(chan error)
|
||||
go p.connCopy(conn, connBackend, errChan)
|
||||
go p.connCopy(connBackend, conn, errChan)
|
||||
go connCopy(conn, connBackend, errChan)
|
||||
go connCopy(connBackend, conn, errChan)
|
||||
|
||||
err = <-errChan
|
||||
if err != nil {
|
||||
|
@ -46,8 +46,12 @@ func (p *Proxy) ServeUDP(conn *Conn) {
|
|||
<-errChan
|
||||
}
|
||||
|
||||
func (p Proxy) connCopy(dst io.WriteCloser, src io.Reader, errCh chan error) {
|
||||
_, err := io.Copy(dst, src)
|
||||
func connCopy(dst io.WriteCloser, src io.Reader, errCh chan error) {
|
||||
// The buffer is initialized to the maximum UDP datagram size,
|
||||
// to make sure that the whole UDP datagram is read or written atomically (no data is discarded).
|
||||
buffer := make([]byte, maxDatagramSize)
|
||||
|
||||
_, err := io.CopyBuffer(dst, src, buffer)
|
||||
errCh <- err
|
||||
|
||||
if err := dst.Close(); err != nil {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue