Merge branch v3.0 into master

This commit is contained in:
Fernandez Ludovic 2024-04-23 13:25:25 +02:00
commit 9d8fd24730
119 changed files with 16917 additions and 500 deletions

View file

@ -12,7 +12,7 @@ env:
jobs:
build-webui:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code
@ -35,7 +35,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-22.04, macos-latest, windows-latest ]
os: [ ubuntu-latest, macos-latest, windows-latest ]
needs:
- build-webui

View file

@ -9,7 +9,7 @@ jobs:
docs:
name: Check, verify and build documentation
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code

View file

@ -14,7 +14,7 @@ jobs:
docs:
name: Doc Process
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
if: github.repository == 'traefik/traefik'
steps:

View file

@ -15,7 +15,7 @@ jobs:
experimental:
if: github.repository == 'traefik/traefik'
name: Build experimental image on branch
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:

View file

@ -15,7 +15,7 @@ env:
jobs:
test-conformance:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Check out code
@ -31,12 +31,5 @@ jobs:
- name: Avoid generating webui
run: touch webui/static/index.html
- name: Build binary
run: make binary
- name: Setcap
run: |
sudo setcap 'cap_net_bind_service=+ep' dist/linux/amd64/traefik
- name: K8s Gateway API conformance test
run: make test-gateway-api-conformance-ci
run: make test-gateway-api-conformance

View file

@ -12,7 +12,7 @@ env:
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code
@ -32,7 +32,7 @@ jobs:
run: make binary
test-integration:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs:
- build
strategy:

View file

@ -11,7 +11,7 @@ env:
jobs:
test-unit:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code

View file

@ -13,7 +13,7 @@ env:
jobs:
validate:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code
@ -39,7 +39,7 @@ jobs:
run: make validate
validate-generate:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code

View file

@ -1,3 +1,85 @@
## [v3.0.0-rc5](https://github.com/traefik/traefik/tree/v3.0.0-rc4) (2024-04-11)
[All Commits](https://github.com/traefik/traefik/compare/v3.0.0-rc4...v3.0.0-rc5)
**Misc:**
- Merge current v2.11 into v3.0 ([#10604](https://github.com/traefik/traefik/pull/10604) by [ldez](https://github.com/ldez))
## [v2.11.2](https://github.com/traefik/traefik/tree/v2.11.2) (2024-04-11)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.1...v2.11.2)
**Bug fixes:**
- **[server]** Revert LingeringTimeout and change default value for ReadTimeout ([#10599](https://github.com/traefik/traefik/pull/10599) by [kevinpollet](https://github.com/kevinpollet))
- **[server]** Set default ReadTimeout value to 60s ([#10602](https://github.com/traefik/traefik/pull/10602) by [rtribotte](https://github.com/rtribotte))
## [v3.0.0-rc4](https://github.com/traefik/traefik/tree/v3.0.0-rc4) (2024-04-10)
[All Commits](https://github.com/traefik/traefik/compare/v3.0.0-rc3...v3.0.0-rc4)
**Enhancements:**
- **[k8s/gatewayapi]** Add option to set Gateway status address ([#10582](https://github.com/traefik/traefik/pull/10582) by [kevinpollet](https://github.com/kevinpollet))
- **[k8s/gatewayapi]** Handle middlewares in filters extension reference ([#10511](https://github.com/traefik/traefik/pull/10511) by [youkoulayley](https://github.com/youkoulayley))
- **[k8s/gatewayapi]** Toggle support for experimental channel ([#10435](https://github.com/traefik/traefik/pull/10435) by [SantoDE](https://github.com/SantoDE))
- **[k8s/ingress,k8s/crd,k8s,k8s/gatewayapi]** Use runtime.Object in routerTransform ([#10523](https://github.com/traefik/traefik/pull/10523) by [juliens](https://github.com/juliens))
- **[nomad]** Allow empty services ([#10375](https://github.com/traefik/traefik/pull/10375) by [chrispruitt](https://github.com/chrispruitt))
- **[webui,middleware,k8s/gatewayapi]** Support RequestHeaderModifier filter ([#10521](https://github.com/traefik/traefik/pull/10521) by [rtribotte](https://github.com/rtribotte))
**Bug fixes:**
- **[docker]** Fix struct names in comment ([#10503](https://github.com/traefik/traefik/pull/10503) by [hishope](https://github.com/hishope))
- **[logs]** Avoid cumulative send anonymous usage log ([#10579](https://github.com/traefik/traefik/pull/10579) by [mmatur](https://github.com/mmatur))
- **[rules]** Support regexp in path/pathprefix in matcher v2 ([#10546](https://github.com/traefik/traefik/pull/10546) by [youkoulayley](https://github.com/youkoulayley))
- **[webui]** Add missing Docker Swarm logo ([#10529](https://github.com/traefik/traefik/pull/10529) by [ldez](https://github.com/ldez))
**Documentation:**
- Fix typo and improve explanation on internal resources ([#10563](https://github.com/traefik/traefik/pull/10563) by [mloiseleur](https://github.com/mloiseleur))
- Fix typo in dialer_test.go ([#10552](https://github.com/traefik/traefik/pull/10552) by [eltociear](https://github.com/eltociear))
**Misc:**
- Merge branch v2.11 into v3.0 ([#10587](https://github.com/traefik/traefik/pull/10587) by [kevinpollet](https://github.com/kevinpollet))
- Merge current v2.11 into v3.0 ([#10566](https://github.com/traefik/traefik/pull/10566) by [mmatur](https://github.com/mmatur))
- Merge current v2.11 into v3.0 ([#10564](https://github.com/traefik/traefik/pull/10564) by [ldez](https://github.com/ldez))
## [v2.11.1](https://github.com/traefik/traefik/tree/v2.11.1) (2024-04-10)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.0...v2.11.1)
**Bug fixes:**
- **[acme,tls]** Enforce handling of ACME-TLS/1 challenges ([#10536](https://github.com/traefik/traefik/pull/10536) by [rtribotte](https://github.com/rtribotte))
- **[acme]** Update go-acme/lego to v4.16.1 ([#10508](https://github.com/traefik/traefik/pull/10508) by [ldez](https://github.com/ldez))
- **[acme]** Close created file in ACME local store CheckFile func ([#10574](https://github.com/traefik/traefik/pull/10574) by [testwill](https://github.com/testwill))
- **[docker,http3]** Update to quic-go v0.42.0 and docker/cli v24.0.9 ([#10572](https://github.com/traefik/traefik/pull/10572) by [mloiseleur](https://github.com/mloiseleur))
- **[docker,marathon,rancher,ecs,tls,nomad]** Allow to configure TLSStore default generated certificate with labels ([#10439](https://github.com/traefik/traefik/pull/10439) by [kevinpollet](https://github.com/kevinpollet))
- **[ecs]** Adjust ECS network interface detection logic ([#10550](https://github.com/traefik/traefik/pull/10550) by [amaxine](https://github.com/amaxine))
- **[logs,tls]** Fix log when default TLSStore and TLSOptions are defined multiple times ([#10499](https://github.com/traefik/traefik/pull/10499) by [rtribotte](https://github.com/rtribotte))
- **[middleware]** Allow empty replacement with ReplacePathRegex middleware ([#10538](https://github.com/traefik/traefik/pull/10538) by [rtribotte](https://github.com/rtribotte))
- **[plugins]** Update Yaegi to v0.16.1 ([#10565](https://github.com/traefik/traefik/pull/10565) by [ldez](https://github.com/ldez))
- **[provider,rules]** Don't allow routers higher than internal ones ([#10428](https://github.com/traefik/traefik/pull/10428) by [ldez](https://github.com/ldez))
- **[rules]** Reserve priority range for internal routers ([#10541](https://github.com/traefik/traefik/pull/10541) by [youkoulayley](https://github.com/youkoulayley))
- **[server,tcp]** Introduce Lingering Timeout ([#10569](https://github.com/traefik/traefik/pull/10569) by [rtribotte](https://github.com/rtribotte))
- **[tcp]** Enforce failure for TCP HostSNI with hostname ([#10540](https://github.com/traefik/traefik/pull/10540) by [youkoulayley](https://github.com/youkoulayley))
- **[tracing]** Bump Elastic APM to v2.4.8 ([#10512](https://github.com/traefik/traefik/pull/10512) by [rtribotte](https://github.com/rtribotte))
- **[webui]** Fix dashboard exposition through a router ([#10518](https://github.com/traefik/traefik/pull/10518) by [mmatur](https://github.com/mmatur))
- **[webui]** Display IPAllowlist middleware configuration in dashboard ([#10459](https://github.com/traefik/traefik/pull/10459) by [youkoulayley](https://github.com/youkoulayley))
- **[webui]** Make text more readable in dark mode ([#10473](https://github.com/traefik/traefik/pull/10473) by [hood](https://github.com/hood))
- **[webui]** Migrate to Quasar 2.x and Vue.js 3.x ([#10416](https://github.com/traefik/traefik/pull/10416) by [andsarr](https://github.com/andsarr))
- **[webui]** Add a horizontal scroll for the mobile view ([#10480](https://github.com/traefik/traefik/pull/10480) by [framebassman](https://github.com/framebassman))
**Documentation:**
- **[acme]** Update gandiv5 env variable in providers table ([#10506](https://github.com/traefik/traefik/pull/10506) by [dominiwe](https://github.com/dominiwe))
- **[acme]** Fix multiple dns provider documentation ([#10496](https://github.com/traefik/traefik/pull/10496) by [mmatur](https://github.com/mmatur))
- **[docker]** Fix paragraph in entrypoints and Docker docs ([#10491](https://github.com/traefik/traefik/pull/10491) by [luigir-it](https://github.com/luigir-it))
- **[k8s]** Improve middleware example ([#10532](https://github.com/traefik/traefik/pull/10532) by [mloiseleur](https://github.com/mloiseleur))
- **[metrics]** Fix host header mention in prometheus metrics doc ([#10502](https://github.com/traefik/traefik/pull/10502) by [MorphBonehunter](https://github.com/MorphBonehunter))
- **[metrics]** Fix typo in statsd metrics docs ([#10437](https://github.com/traefik/traefik/pull/10437) by [xpac1985](https://github.com/xpac1985))
- **[middleware]** Improve excludedIPs example with IPWhiteList and IPAllowList middleware ([#10554](https://github.com/traefik/traefik/pull/10554) by [mloiseleur](https://github.com/mloiseleur))
- **[nomad]** Improve documentation about Nomad ACL minimum rights ([#10482](https://github.com/traefik/traefik/pull/10482) by [Thadir](https://github.com/Thadir))
- **[server]** Add specification for TCP TLS routers in documentation ([#10510](https://github.com/traefik/traefik/pull/10510) by [shivanipawar00](https://github.com/shivanipawar00))
- **[tls]** Fix default value for peerCertURI option ([#10470](https://github.com/traefik/traefik/pull/10470) by [marcmognol](https://github.com/marcmognol))
- Update releases page ([#10449](https://github.com/traefik/traefik/pull/10449) by [ldez](https://github.com/ldez))
- Update releases page ([#10443](https://github.com/traefik/traefik/pull/10443) by [ldez](https://github.com/ldez))
- Add youkoulayley to maintainers ([#10517](https://github.com/traefik/traefik/pull/10517) by [emilevauge](https://github.com/emilevauge))
- Add sdelicata to maintainers ([#10515](https://github.com/traefik/traefik/pull/10515) by [emilevauge](https://github.com/emilevauge))
**Misc:**
- **[webui]** Modify the Hub Button ([#10583](https://github.com/traefik/traefik/pull/10583) by [mdeliatf](https://github.com/mdeliatf))
## [v3.0.0-rc3](https://github.com/traefik/traefik/tree/v3.0.0-rc3) (2024-03-13)
[All Commits](https://github.com/traefik/traefik/compare/v3.0.0-rc2...v3.0.0-rc3)

View file

@ -102,15 +102,8 @@ test-integration: binary
.PHONY: test-gateway-api-conformance
#? test-gateway-api-conformance: Run the conformance tests
test-gateway-api-conformance: binary
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -test.run K8sConformanceSuite -k8sConformance=true $(TESTFLAGS)
## TODO: Need to be fixed to work in all situations.
.PHONY: test-gateway-api-conformance-ci
#? test-gateway-api-conformance-ci: Run the conformance tests
test-gateway-api-conformance-ci:
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -test.run K8sConformanceSuite -k8sConformance=true $(TESTFLAGS)
test-gateway-api-conformance: build-image-dirty
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -test.run K8sConformanceSuite -k8sConformance $(TESTFLAGS)
.PHONY: pull-images
#? pull-images: Pull all Docker images to avoid timeout during integration tests

View file

@ -593,16 +593,16 @@ func checkNewVersion() {
}
func stats(staticConfiguration *static.Configuration) {
logger := log.Info()
logger := log.With().Logger()
if staticConfiguration.Global.SendAnonymousUsage {
logger.Msg(`Stats collection is enabled.`)
logger.Msg(`Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.`)
logger.Msg(`Help us improve Traefik by leaving this feature on :)`)
logger.Msg(`More details on: https://doc.traefik.io/traefik/contributing/data-collection/`)
logger.Info().Msg(`Stats collection is enabled.`)
logger.Info().Msg(`Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.`)
logger.Info().Msg(`Help us improve Traefik by leaving this feature on :)`)
logger.Info().Msg(`More details on: https://doc.traefik.io/traefik/contributing/data-collection/`)
collect(staticConfiguration)
} else {
logger.Msg(`
logger.Info().Msg(`
Stats collection is disabled.
Help us improve Traefik by turning this feature on :)
More details on: https://doc.traefik.io/traefik/contributing/data-collection/

View file

@ -93,7 +93,7 @@ The example below is a file provider only version (`yaml`) of what this configur
```yaml tab="Static configuration"
# traefik.yml
entrypoints:
entryPoints:
web:
address: :80

View file

@ -116,8 +116,8 @@ Please check the [configuration examples below](#configuration-examples) for mor
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
# ...
--certificatesresolvers.myresolver.acme.email=your-email@example.com
--certificatesresolvers.myresolver.acme.storage=acme.json
@ -241,8 +241,8 @@ when using the `HTTP-01` challenge, `certificatesresolvers.myresolver.acme.httpc
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
# ...
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
```

View file

@ -8,11 +8,11 @@ description: "Learn how to use IPAllowList in HTTP middleware for limiting clien
Limiting Clients to Specific IPs
{: .subtitle }
IPAllowList accepts / refuses requests based on the client IP.
IPAllowList limits allowed requests based on the client IP.
## Configuration Examples
```yaml tab="Docker & Swarm"
```yaml tab="Docker"
# Accepts request from defined IP
labels:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
@ -35,6 +35,18 @@ spec:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32,192.168.1.7"
}
```
```yaml tab="Rancher"
# Accepts request from defined IP
labels:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="File (YAML)"
# Accepts request from defined IP
http:
@ -57,6 +69,8 @@ http:
### `sourceRange`
_Required_
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).
### `ipStrategy`
@ -83,7 +97,7 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
```yaml tab="Docker & Swarm"
```yaml tab="Docker"
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
labels:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
@ -111,6 +125,20 @@ spec:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32, 192.168.1.7",
"traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth": "2"
}
```
```yaml tab="Rancher"
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
labels:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2"
```
```yaml tab="File (YAML)"
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
http:
@ -149,9 +177,10 @@ http:
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` |
| `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` |
```yaml tab="Docker & Swarm"
```yaml tab="Docker"
# Exclude from `X-Forwarded-For`
labels:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
@ -163,6 +192,9 @@ metadata:
name: test-ipallowlist
spec:
ipAllowList:
sourceRange:
- 127.0.0.1/32
- 192.168.1.0/24
ipStrategy:
excludedIPs:
- 127.0.0.1/32
@ -171,25 +203,44 @@ spec:
```yaml tab="Consul Catalog"
# Exclude from `X-Forwarded-For`
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
"traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7"
}
```
```yaml tab="Rancher"
# Exclude from `X-Forwarded-For`
labels:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```yaml tab="File (YAML)"
# Exclude from `X-Forwarded-For`
http:
middlewares:
test-ipallowlist:
ipAllowList:
sourceRange:
- 127.0.0.1/32
- 192.168.1.0/24
ipStrategy:
excludedIPs:
- "127.0.0.1/32"
- "192.168.1.7"
- 127.0.0.1/32
- 192.168.1.7
```
```toml tab="File (TOML)"
# Exclude from `X-Forwarded-For`
[http.middlewares]
[http.middlewares.test-ipallowlist.ipAllowList]
sourceRange = ["127.0.0.1/32", "192.168.1.0/24"]
[http.middlewares.test-ipallowlist.ipAllowList.ipStrategy]
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
```

View file

@ -10,7 +10,7 @@ Limiting Clients to Specific IPs
![IPWhiteList](../../assets/img/middleware/ipwhitelist.png)
IPWhiteList accepts / refuses requests based on the client IP.
IPWhiteList limits allowed requests based on the client IP.
!!! warning
@ -63,6 +63,8 @@ http:
### `sourceRange`
_Required_
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).
### `ipStrategy`
@ -158,6 +160,7 @@ http:
```yaml tab="Docker"
# Exclude from `X-Forwarded-For`
labels:
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
@ -170,6 +173,9 @@ metadata:
spec:
ipWhiteList:
ipStrategy:
sourceRange:
- 127.0.0.1/32
- 192.168.1.0/24
excludedIPs:
- 127.0.0.1/32
- 192.168.1.7
@ -177,6 +183,7 @@ spec:
```yaml tab="Consul Catalog"
# Exclude from `X-Forwarded-For`
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
@ -186,16 +193,20 @@ http:
middlewares:
test-ipwhitelist:
ipWhiteList:
sourceRange:
- 127.0.0.1/32
- 192.168.1.0/24
ipStrategy:
excludedIPs:
- "127.0.0.1/32"
- "192.168.1.7"
- 127.0.0.1/32
- 192.168.1.7
```
```toml tab="File (TOML)"
# Exclude from `X-Forwarded-For`
[http.middlewares]
[http.middlewares.test-ipwhitelist.ipWhiteList]
sourceRange = ["127.0.0.1/32", "192.168.1.0/24"]
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
```

View file

@ -8,7 +8,7 @@ description: "Learn how to use IPAllowList in TCP middleware for limiting client
Limiting Clients to Specific IPs
{: .subtitle }
IPAllowList accepts / refuses connections based on the client IP.
IPAllowList limits allowed requests based on the client IP.
## Configuration Examples

View file

@ -354,7 +354,7 @@ To apply a redirection:
```
```bash tab="CLI"
--entrypoints=Name:web Address::80 Redirect.EntryPoint:websecure
--entryPoints=Name:web Address::80 Redirect.EntryPoint:websecure
--entryPoints='Name:websecure Address::443 TLS'
```
@ -394,10 +394,10 @@ To apply a redirection:
```bash tab="CLI"
## static configuration
--entrypoints.web.address=:80
--entrypoints.web.http.redirections.entrypoint.to=websecure
--entrypoints.web.http.redirections.entrypoint.scheme=https
--entrypoints.websecure.address=:443
--entryPoints.web.address=:80
--entryPoints.web.http.redirections.entrypoint.to=websecure
--entryPoints.web.http.redirections.entrypoint.scheme=https
--entryPoints.websecure.address=:443
--providers.docker=true
```
@ -750,8 +750,8 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--certificatesresolvers.myresolver.acme.email=your-email@example.com
--certificatesresolvers.myresolver.acme.storage=acme.json
--certificatesresolvers.myresolver.acme.tlschallenge=true
@ -1078,7 +1078,7 @@ To activate the dashboard, you can either:
routers:
api:
rule: Host(`traefik.docker.localhost`)
entrypoints:
entryPoints:
- websecure
service: api@internal
middlewares:

View file

@ -724,7 +724,7 @@ Here are two possible transition strategies:
Please check the [OpenTelemetry Tracing provider documention](../observability/tracing/opentelemetry.md) for more information.
#### Internal Resources Observability (AccessLogs, Metrics and Tracing)
#### Internal Resources Observability
In v3, observability for internal routers or services (e.g.: `ping@internal`) is disabled by default.
To enable it one should use the new `addInternals` option for AccessLogs, Metrics or Tracing.
@ -732,4 +732,4 @@ Please take a look at the observability documentation for more information:
- [AccessLogs](../observability/access-logs.md#addinternals)
- [Metrics](../observability/metrics/overview.md#addinternals)
- [AccessLogs](../observability/tracing/overview.md#addinternals)
- [Tracing](../observability/tracing/overview.md#addinternals)

View file

@ -580,3 +580,63 @@ the maximum user-defined router priority value is:
- `(MaxInt32 - 1000)` for 32-bit platforms,
- `(MaxInt64 - 1000)` for 64-bit platforms.
### EntryPoint.Transport.RespondingTimeouts.<Timeout>
Starting with `v2.11.1` the following timeout options are deprecated:
- `<entryPoint>.transport.respondingTimeouts.readTimeout`
- `<entryPoint>.transport.respondingTimeouts.writeTimeout`
- `<entryPoint>.transport.respondingTimeouts.idleTimeout`
They have been replaced by:
- `<entryPoint>.transport.respondingTimeouts.http.readTimeout`
- `<entryPoint>.transport.respondingTimeouts.http.writeTimeout`
- `<entryPoint>.transport.respondingTimeouts.http.idleTimeout`
### EntryPoint.Transport.RespondingTimeouts.TCP.LingeringTimeout
Starting with `v2.11.1` a new `lingeringTimeout` entryPoints option has been introduced, with a default value of 2s.
The lingering timeout defines the maximum duration between each TCP read operation on the connection.
As a layer 4 timeout, it applies during HTTP handling but respects the configured HTTP server `readTimeout`.
This change avoids Traefik instances with the default configuration hanging while waiting for bytes to be read on the connection.
We suggest to adapt this value accordingly to your situation.
The new default value is purposely narrowed and can close the connection too early.
Increasing the `lingeringTimeout` value could be the solution notably if you are dealing with the following errors:
- TCP: `Error while handling TCP connection: readfrom tcp X.X.X.X:X->X.X.X.X:X: read tcp X.X.X.X:X->X.X.X.X:X: i/o timeout`
- HTTP: `'499 Client Closed Request' caused by: context canceled`
- HTTP: `ReverseProxy read error during body copy: read tcp X.X.X.X:X->X.X.X.X:X: use of closed network connection`
## v2.11.2
### LingeringTimeout
Starting with `v2.11.2` the `<entrypoint>.transport.respondingTimeouts.tcp.lingeringTimeout` introduced in `v2.11.1` has been removed.
### RespondingTimeouts.TCP and RespondingTimeouts.HTTP
Starting with `v2.11.2` the `respondingTimeouts.tcp` and `respondingTimeouts.http` sections introduced in `v2.11.1` have been removed.
To configure the responding timeouts, please use the [`respondingTimeouts`](../routing/entrypoints.md#respondingtimeouts) section.
### EntryPoint.Transport.RespondingTimeouts.ReadTimeout
Starting with `v2.11.2` the entryPoints [`readTimeout`](../routing/entrypoints.md#respondingtimeouts) option default value changed to 60 seconds.
For HTTP, this option defines the maximum duration for reading the entire request, including the body.
For TCP, this option defines the maximum duration for the first bytes to be read on the connection.
The default value was previously set to zero, which means no timeout.
This change has been done to avoid Traefik instances with the default configuration to be hanging forever while waiting for bytes to be read on the connection.
Increasing the `readTimeout` value could be the solution notably if you are dealing with the following errors:
- TCP: `Error while handling TCP connection: readfrom tcp X.X.X.X:X->X.X.X.X:X: read tcp X.X.X.X:X->X.X.X.X:X: i/o timeout`
- HTTP: `'499 Client Closed Request' caused by: context canceled`
- HTTP: `ReverseProxy read error during body copy: read tcp X.X.X.X:X->X.X.X.X:X: use of closed network connection`

View file

@ -30,7 +30,7 @@ accessLog: {}
_Optional, Default="false"_
Enables accessLogs for internal resources.
Enables accessLogs for internal resources (e.g.: `ping@internal`).
```yaml tab="File (YAML)"
accesslog:

View file

@ -21,7 +21,7 @@ and [Kubernetes](https://grafana.com/grafana/dashboards/17347) deployments.
_Optional, Default="false"_
Enables metrics for internal resources.
Enables metrics for internal resources (e.g.: `ping@internals`).
```yaml tab="File (YAML)"
metrics:

View file

@ -36,7 +36,7 @@ tracing: {}
_Optional, Default="false"_
Enables tracing for internal resources.
Enables tracing for internal resources (e.g.: `ping@internal`).
```yaml tab="File (YAML)"
tracing:

View file

@ -212,6 +212,85 @@ providers:
--providers.kubernetesgateway.namespaces=default,production
```
### `statusAddress`
#### `ip`
_Optional, Default: ""_
This IP will get copied to the Gateway `status.addresses`, and currently only supports one IP value (IPv4 or IPv6).
```yaml tab="File (YAML)"
providers:
kubernetesGateway:
statusAddress:
ip: "1.2.3.4"
# ...
```
```toml tab="File (TOML)"
[providers.kubernetesGateway.statusAddress]
ip = "1.2.3.4"
# ...
```
```bash tab="CLI"
--providers.kubernetesgateway.statusaddress.ip=1.2.3.4
```
#### `hostname`
_Optional, Default: ""_
This Hostname will get copied to the Gateway `status.addresses`.
```yaml tab="File (YAML)"
providers:
kubernetesGateway:
statusAddress:
hostname: "example.net"
# ...
```
```toml tab="File (TOML)"
[providers.kubernetesGateway.statusAddress]
hostname = "example.net"
# ...
```
```bash tab="CLI"
--providers.kubernetesgateway.statusaddress.hostname=example.net
```
#### `service`
_Optional_
The Kubernetes service to copy status addresses from.
When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the gateways.
```yaml tab="File (YAML)"
providers:
kubernetesGateway:
statusAddress:
service:
namespace: default
name: foo
# ...
```
```toml tab="File (TOML)"
[providers.kubernetesGateway.statusAddress.service]
namespace = "default"
name = "foo"
# ...
```
```bash tab="CLI"
--providers.kubernetesgateway.statusaddress.service.namespace=default
--providers.kubernetesgateway.statusaddress.service.name=foo
```
### `experimentalChannel`
_Optional, Default: false_

View file

@ -163,6 +163,7 @@ providers:
_Optional, Default=""_
Token is used to provide a per-request ACL token, if Nomad ACLs are enabled.
The appropriate ACL privilege for this token is 'read-job', as outlined in the [Nomad documentation on ACL](https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-policies).
```yaml tab="File (YAML)"
providers:
@ -511,3 +512,27 @@ providers:
--providers.nomad.namespaces=ns1,ns2
# ...
```
### `allowEmptyServices`
_Optional, Default: false_
If the parameter is set to `true`,
it allows the creation of an empty [servers load balancer](../routing/services/index.md#servers-load-balancer) if the targeted Nomad service has no endpoints available. This results in a `503` HTTP response instead of a `404`.
```yaml tab="File (YAML)"
providers:
nomad:
allowEmptyServices: true
# ...
```
```toml tab="File (TOML)"
[providers.nomad]
allowEmptyServices = true
# ...
```
```bash tab="CLI"
--providers.nomad.allowEmptyServices=true
```

View file

@ -835,6 +835,10 @@ spec:
breaker will try to recover (as soon as it is in recovering
state).
x-kubernetes-int-or-string: true
responseCode:
description: ResponseCode is the status code that the circuit
breaker will return while it is in the open state.
type: integer
type: object
compress:
description: |-
@ -1331,7 +1335,7 @@ spec:
ipAllowList:
description: |-
IPAllowList holds the IP allowlist middleware configuration.
This middleware accepts / refuses requests based on the client IP.
This middleware limits allowed requests based on the client IP.
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/
properties:
ipStrategy:
@ -1385,7 +1389,7 @@ spec:
type: object
sourceRange:
description: SourceRange defines the set of allowed IPs (or ranges
of allowed IPs by using CIDR notation).
of allowed IPs by using CIDR notation). Required.
items:
type: string
type: array

View file

@ -27,8 +27,8 @@ spec:
- name: traefik
image: traefik:v3.0
args:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --experimental.kubernetesgateway
- --providers.kubernetesgateway

View file

@ -172,6 +172,10 @@ spec:
breaker will try to recover (as soon as it is in recovering
state).
x-kubernetes-int-or-string: true
responseCode:
description: ResponseCode is the status code that the circuit
breaker will return while it is in the open state.
type: integer
type: object
compress:
description: |-
@ -668,7 +672,7 @@ spec:
ipAllowList:
description: |-
IPAllowList holds the IP allowlist middleware configuration.
This middleware accepts / refuses requests based on the client IP.
This middleware limits allowed requests based on the client IP.
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/
properties:
ipStrategy:
@ -722,7 +726,7 @@ spec:
type: object
sourceRange:
description: SourceRange defines the set of allowed IPs (or ranges
of allowed IPs by using CIDR notation).
of allowed IPs by using CIDR notation). Required.
items:
type: string
type: array

View file

@ -202,7 +202,7 @@ Duration to keep accepting requests before Traefik initiates the graceful shutdo
IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. (Default: ```180```)
`--entrypoints.<name>.transport.respondingtimeouts.readtimeout`:
ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```0```)
ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```60```)
`--entrypoints.<name>.transport.respondingtimeouts.writetimeout`:
WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. (Default: ```0```)
@ -738,6 +738,21 @@ Kubernetes label selector to select specific GatewayClasses.
`--providers.kubernetesgateway.namespaces`:
Kubernetes namespaces.
`--providers.kubernetesgateway.statusaddress.hostname`:
Hostname used for Kubernetes Gateway status address.
`--providers.kubernetesgateway.statusaddress.ip`:
IP used to set Kubernetes Gateway status address.
`--providers.kubernetesgateway.statusaddress.service`:
Published Kubernetes Service to copy status addresses from.
`--providers.kubernetesgateway.statusaddress.service.name`:
Name of the Kubernetes service.
`--providers.kubernetesgateway.statusaddress.service.namespace`:
Namespace of the Kubernetes service.
`--providers.kubernetesgateway.throttleduration`:
Kubernetes refresh throttle duration (Default: ```0```)
@ -789,6 +804,9 @@ Kubernetes bearer token (not needed for in-cluster client). It accepts either a
`--providers.nomad`:
Enable Nomad backend with default settings. (Default: ```false```)
`--providers.nomad.allowemptyservices`:
Allow the creation of services without endpoints. (Default: ```false```)
`--providers.nomad.constraints`:
Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service.

View file

@ -202,7 +202,7 @@ Duration to keep accepting requests before Traefik initiates the graceful shutdo
IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. (Default: ```180```)
`TRAEFIK_ENTRYPOINTS_<NAME>_TRANSPORT_RESPONDINGTIMEOUTS_READTIMEOUT`:
ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```0```)
ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```60```)
`TRAEFIK_ENTRYPOINTS_<NAME>_TRANSPORT_RESPONDINGTIMEOUTS_WRITETIMEOUT`:
WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. (Default: ```0```)
@ -738,6 +738,21 @@ Kubernetes label selector to select specific GatewayClasses.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_NAMESPACES`:
Kubernetes namespaces.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_STATUSADDRESS_HOSTNAME`:
Hostname used for Kubernetes Gateway status address.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_STATUSADDRESS_IP`:
IP used to set Kubernetes Gateway status address.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_STATUSADDRESS_SERVICE`:
Published Kubernetes Service to copy status addresses from.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_STATUSADDRESS_SERVICE_NAME`:
Name of the Kubernetes service.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_STATUSADDRESS_SERVICE_NAMESPACE`:
Namespace of the Kubernetes service.
`TRAEFIK_PROVIDERS_KUBERNETESGATEWAY_THROTTLEDURATION`:
Kubernetes refresh throttle duration (Default: ```0```)
@ -789,6 +804,9 @@ Kubernetes bearer token (not needed for in-cluster client). It accepts either a
`TRAEFIK_PROVIDERS_NOMAD`:
Enable Nomad backend with default settings. (Default: ```false```)
`TRAEFIK_PROVIDERS_NOMAD_ALLOWEMPTYSERVICES`:
Allow the creation of services without endpoints. (Default: ```false```)
`TRAEFIK_PROVIDERS_NOMAD_CONSTRAINTS`:
Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service.

View file

@ -147,6 +147,12 @@
labelSelector = "foobar"
throttleDuration = "42s"
experimentalChannel = true
[providers.kubernetesGateway.statusAddress]
ip = "foobar"
hostname = "foobar"
[providers.kubernetesGateway.statusAddress.service]
name = "foobar"
namespace = "foobar"
[providers.rest]
insecure = true
[providers.consulCatalog]
@ -185,6 +191,7 @@
stale = true
exposedByDefault = true
refreshInterval = "42s"
allowEmptyServices = true
namespaces = ["foobar", "foobar"]
[providers.nomad.endpoint]
address = "foobar"

View file

@ -164,6 +164,12 @@ providers:
labelSelector: foobar
throttleDuration: 42s
experimentalChannel: true
statusAddress:
ip: foobar
hostname: foobar
service:
name: foobar
namespace: foobar
rest:
insecure: true
consulCatalog:
@ -216,6 +222,7 @@ providers:
stale: true
exposedByDefault: true
refreshInterval: 42s
allowEmptyServices: true
namespaces:
- foobar
- foobar

View file

@ -227,8 +227,8 @@ If both TCP and UDP are wanted for the same port, two entryPoints definitions ar
```
```bash tab="CLI"
--entrypoints.specificIPv4.address=192.168.2.7:8888
--entrypoints.specificIPv6.address=[2001:db8::1]:8888
--entryPoints.specificIPv4.address=192.168.2.7:8888
--entryPoints.specificIPv6.address=[2001:db8::1]:8888
```
Full details for how to specify `address` can be found in [net.Listen](https://golang.org/pkg/net/#Listen) (and [net.Dial](https://golang.org/pkg/net/#Dial)) of the doc for go.
@ -270,8 +270,8 @@ reloading the static configuration without any service downtime.
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.web.reusePort=true
--entryPoints.web.address=:80
--entryPoints.web.reusePort=true
```
Now it is possible to run multiple Traefik processes with the same EntryPoint configuration.
@ -298,10 +298,10 @@ reloading the static configuration without any service downtime.
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.web.reusePort=true
--entrypoints.privateWeb.address=192.168.1.2:80
--entrypoints.privateWeb.reusePort=true
--entryPoints.web.address=:80
--entryPoints.web.reusePort=true
--entryPoints.privateWeb.address=192.168.1.2:80
--entryPoints.privateWeb.reusePort=true
```
Requests to `192.168.1.2:80` will only be handled by routers that have `privateWeb` as the entry point.
@ -349,9 +349,9 @@ EntryPoints in this list are used (by default) on HTTP and TCP routers that do n
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.websecure.asDefault=true
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--entryPoints.websecure.asDefault=true
```
### HTTP/2
@ -401,7 +401,7 @@ entryPoints:
```
```bash tab="CLI"
--entrypoints.name.http3
--entryPoints.name.http3
```
??? info "HTTP/3 uses UDP+TLS"
@ -433,7 +433,7 @@ It can be used to override the authority in the `alt-svc` header, for example if
```
```bash tab="CLI"
--entrypoints.name.http3.advertisedport=443
--entryPoints.name.http3.advertisedport=443
```
### Forwarded Headers
@ -509,13 +509,14 @@ Setting them has no effect for UDP entryPoints.
??? info "`transport.respondingTimeouts.readTimeout`"
_Optional, Default=0s_
_Optional, Default=60s_
`readTimeout` is the maximum duration for reading the entire request, including the body.
If zero, no timeout exists.
Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).
If no units are provided, the value is parsed assuming seconds.
We strongly suggest to adapt this value accordingly to the your needs.
```yaml tab="File (YAML)"
## Static configuration
@ -869,10 +870,10 @@ This whole section is dedicated to options, keyed by entry point, that will appl
```
```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.web.http.redirections.entryPoint.to=websecure
--entrypoints.web.http.redirections.entryPoint.scheme=https
--entrypoints.websecure.address=:443
--entryPoints.web.address=:80
--entryPoints.web.http.redirections.entryPoint.to=websecure
--entryPoints.web.http.redirections.entryPoint.scheme=https
--entryPoints.websecure.address=:443
```
#### `entryPoint`
@ -907,7 +908,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
```
```bash tab="CLI"
--entrypoints.foo.http.redirections.entryPoint.to=websecure
--entryPoints.foo.http.redirections.entryPoint.to=websecure
```
??? info "`entryPoint.scheme`"
@ -937,7 +938,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
```
```bash tab="CLI"
--entrypoints.foo.http.redirections.entryPoint.scheme=https
--entryPoints.foo.http.redirections.entryPoint.scheme=https
```
??? info "`entryPoint.permanent`"
@ -967,7 +968,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
```
```bash tab="CLI"
--entrypoints.foo.http.redirections.entrypoint.permanent=true
--entryPoints.foo.http.redirections.entrypoint.permanent=true
```
??? info "`entryPoint.priority`"
@ -997,7 +998,7 @@ This section is a convenience to enable (permanent) redirecting of all incoming
```
```bash tab="CLI"
--entrypoints.foo.http.redirections.entrypoint.priority=10
--entryPoints.foo.http.redirections.entrypoint.priority=10
```
### EncodeQuerySemicolons
@ -1025,8 +1026,8 @@ entryPoints:
```
```bash tab="CLI"
--entrypoints.websecure.address=:443
--entrypoints.websecure.http.encodequerysemicolons=true
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.encodequerysemicolons=true
```
#### Examples
@ -1061,8 +1062,8 @@ entryPoints:
```
```bash tab="CLI"
--entrypoints.websecure.address=:443
--entrypoints.websecure.http.middlewares=auth@file,strip@file
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.middlewares=auth@file,strip@file
```
### TLS
@ -1108,13 +1109,13 @@ entryPoints:
```
```bash tab="CLI"
--entrypoints.websecure.address=:443
--entrypoints.websecure.http.tls.options=foobar
--entrypoints.websecure.http.tls.certResolver=leresolver
--entrypoints.websecure.http.tls.domains[0].main=example.com
--entrypoints.websecure.http.tls.domains[0].sans=foo.example.com,bar.example.com
--entrypoints.websecure.http.tls.domains[1].main=test.com
--entrypoints.websecure.http.tls.domains[1].sans=foo.test.com,bar.test.com
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.tls.options=foobar
--entryPoints.websecure.http.tls.certResolver=leresolver
--entryPoints.websecure.http.tls.domains[0].main=example.com
--entryPoints.websecure.http.tls.domains[0].sans=foo.example.com,bar.example.com
--entryPoints.websecure.http.tls.domains[1].main=test.com
--entryPoints.websecure.http.tls.domains[1].sans=foo.test.com,bar.test.com
```
??? example "Let's Encrypt"
@ -1137,8 +1138,8 @@ entryPoints:
```
```bash tab="CLI"
--entrypoints.websecure.address=:443
--entrypoints.websecure.http.tls.certResolver=leresolver
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.tls.certResolver=leresolver
```
## UDP Options
@ -1169,8 +1170,8 @@ entryPoints:
```
```bash tab="CLI"
entrypoints.foo.address=:8000/udp
entrypoints.foo.udp.timeout=10s
--entryPoints.foo.address=:8000/udp
--entryPoints.foo.udp.timeout=10s
```
{!traefik-for-business-applications.md!}

View file

@ -53,9 +53,9 @@ The Kubernetes Ingress Controller, The Custom Resource Way.
- --log.level=DEBUG
- --api
- --api.insecure
- --entrypoints.web.address=:80
- --entrypoints.tcpep.address=:8000
- --entrypoints.udpep.address=:9000/udp
- --entryPoints.web.address=:80
- --entryPoints.tcpep.address=:8000
- --entryPoints.udpep.address=:9000/udp
- --providers.kubernetescrd
ports:
- name: web

View file

@ -234,7 +234,7 @@ Kubernetes cluster before creating `HTTPRoute` objects.
- headers: # [11]
name: foo # [12]
value: bar # [13]
- backendRefs: # [14]
backendRefs: # [14]
- name: whoamitcp # [15]
weight: 1 # [16]
port: 8080 # [17]
@ -251,10 +251,20 @@ Kubernetes cluster before creating `HTTPRoute` objects.
requestRedirect: # [27]
scheme: https # [28]
statusCode: 301 # [29]
- type: RequestHeaderModifier # [30]
requestHeaderModifier: # [31]
set:
- name: X-Foo
value: Bar
add:
- name: X-Bar
value: Foo
remove:
- X-Baz
```
| Ref | Attribute | Description |
|------|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
| [2] | `name` | Name of the referent. |
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
@ -263,7 +273,7 @@ Kubernetes cluster before creating `HTTPRoute` objects.
| [6] | `rules` | A list of HTTP matchers, filters and actions. |
| [7] | `matches` | Conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. |
| [8] | `path` | An HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. |
| [9] | `type` | Type of match against the path Value (supported types: `Exact`, `Prefix`). |
| [9] | `type` | Type of match against the path Value (supported types: `Exact`, `PathPrefix`). |
| [10] | `value` | The value of the HTTP path to match against. |
| [11] | `headers` | Conditions to select a HTTP route by matching HTTP request headers. |
| [12] | `name` | Name of the HTTP header to be matched. |
@ -284,6 +294,8 @@ Kubernetes cluster before creating `HTTPRoute` objects.
| [27] | `requestRedirect` | Configuration of redirect filter. |
| [28] | `scheme` | Scheme is the scheme to be used in the value of the Location header in the response. |
| [29] | `statusCode` | StatusCode is the HTTP status code to be used in response. |
| [30] | `type` | Defines the type of filter; RequestHeaderModifier modifies request headers. |
| [31] | `requestHeaderModifier` | Configuration of RequestHeaderModifier filter. |
### Kind: `TCPRoute`

View file

@ -126,7 +126,7 @@ which in turn will create the resulting routers, services, handlers, etc.
- name: traefik
image: traefik:v3.0
args:
- --entrypoints.web.address=:80
- --entryPoints.web.address=:80
- --providers.kubernetesingress
ports:
- name: web
@ -391,8 +391,8 @@ TLS can be enabled through the [HTTP options](../entrypoints.md#tls) of an Entry
```bash tab="CLI"
# Static configuration
--entrypoints.websecure.address=:443
--entrypoints.websecure.http.tls
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.tls
```
```yaml tab="File (YAML)"
@ -524,8 +524,8 @@ This way, any Ingress attached to this Entrypoint will have TLS termination by d
- name: traefik
image: traefik:v3.0
args:
- --entrypoints.websecure.address=:443
- --entrypoints.websecure.http.tls
- --entryPoints.websecure.address=:443
- --entryPoints.websecure.http.tls
- --providers.kubernetesingress
ports:
- name: websecure
@ -710,7 +710,7 @@ For more options, please refer to the available [annotations](#on-ingress).
- name: traefik
image: traefik:v3.0
args:
- --entrypoints.websecure.address=:443
- --entryPoints.websecure.address=:443
- --providers.kubernetesingress
ports:
- name: websecure

View file

@ -146,9 +146,9 @@ If you want to limit the router scope to a set of entry points, set the `entryPo
```bash tab="CLI"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--entryPoints.other.address=:9090
```
??? example "Listens to Specific EntryPoints"
@ -204,9 +204,9 @@ If you want to limit the router scope to a set of entry points, set the `entryPo
```bash tab="CLI"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--entryPoints.other.address=:9090
```
### Rule
@ -959,9 +959,9 @@ If you want to limit the router scope to a set of entry points, set the entry po
```bash tab="CLI"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--entryPoints.other.address=:9090
```
??? example "Listens to Specific EntryPoints"
@ -1023,9 +1023,9 @@ If you want to limit the router scope to a set of entry points, set the entry po
```bash tab="CLI"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--entryPoints.other.address=:9090
```
### Rule
@ -1610,9 +1610,9 @@ If one wants to limit the router scope to a set of EntryPoints, one should set t
```bash tab="CLI"
## Static configuration
--entrypoints.web.address=":80"
--entrypoints.other.address=":9090/udp"
--entrypoints.streaming.address=":9191/udp"
--entryPoints.web.address=":80"
--entryPoints.other.address=":9090/udp"
--entryPoints.streaming.address=":9191/udp"
```
??? example "Listens to Specific EntryPoints"
@ -1667,9 +1667,9 @@ If one wants to limit the router scope to a set of EntryPoints, one should set t
```bash tab="CLI"
## Static configuration
--entrypoints.web.address=":80"
--entrypoints.other.address=":9090/udp"
--entrypoints.streaming.address=":9191/udp"
--entryPoints.web.address=":80"
--entryPoints.other.address=":9090/udp"
--entryPoints.streaming.address=":9191/udp"
```
### Services

View file

@ -30,8 +30,8 @@ spec:
args:
- --api.insecure
- --accesslog
- --entrypoints.web.Address=:8000
- --entrypoints.websecure.Address=:4443
- --entryPoints.web.Address=:8000
- --entryPoints.websecure.Address=:4443
- --providers.kubernetescrd
- --certificatesresolvers.myresolver.acme.tlschallenge
- --certificatesresolvers.myresolver.acme.email=foo@you.com

View file

@ -10,8 +10,8 @@ services:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.dnschallenge=true"
- "--certificatesresolvers.myresolver.acme.dnschallenge.provider=ovh"
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"

View file

@ -20,8 +20,8 @@ services:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.dnschallenge=true"
- "--certificatesresolvers.myresolver.acme.dnschallenge.provider=ovh"
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"

View file

@ -64,7 +64,7 @@ What changed between the initial setup:
```yaml
command:
# Traefik will listen to incoming request on the port 443 (https)
- "--entrypoints.websecure.address=:443"
- "--entryPoints.websecure.address=:443"
ports:
- "443:443"
```

View file

@ -10,8 +10,8 @@ services:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"

View file

@ -50,7 +50,7 @@ What changed between the basic example:
```yaml
command:
# Traefik will listen to incoming request on the port 443 (https)
- "--entrypoints.websecure.address=:443"
- "--entryPoints.websecure.address=:443"
ports:
- "443:443"
```

View file

@ -10,7 +10,7 @@ services:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.myresolver.acme.email=postmaster@example.com"

View file

@ -50,7 +50,7 @@ What changed between the basic example:
```yaml
command:
# Traefik will listen to incoming request on the port 443 (https)
- "--entrypoints.websecure.address=:443"
- "--entryPoints.websecure.address=:443"
ports:
- "443:443"
```

View file

@ -10,7 +10,7 @@ services:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entryPoints.web.address=:80"
ports:
- "80:80"
- "8080:8080"

View file

@ -86,7 +86,7 @@ Second, you define an entry point, along with the exposure of the matching port
```yaml
command:
# Traefik will listen to incoming request on the port 80 (HTTP)
- "--entrypoints.web.address=:80"
- "--entryPoints.web.address=:80"
ports:
- "80:80"

61
go.mod
View file

@ -12,9 +12,9 @@ require (
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.2-0.20180830191138-d8f796af33cc
github.com/docker/cli v24.0.7+incompatible
github.com/docker/docker v24.0.7+incompatible
github.com/docker/go-connections v0.4.0
github.com/docker/cli v24.0.9+incompatible
github.com/docker/docker v25.0.5+incompatible
github.com/docker/go-connections v0.5.0
github.com/fatih/structs v1.1.0
github.com/fsnotify/fsnotify v1.7.0
github.com/go-acme/lego/v4 v4.16.1
@ -49,14 +49,15 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
github.com/prometheus/client_golang v1.17.0
github.com/prometheus/client_model v0.5.0
github.com/quic-go/quic-go v0.40.1
github.com/quic-go/quic-go v0.42.0
github.com/rs/zerolog v1.29.0
github.com/sirupsen/logrus v1.9.3
github.com/spiffe/go-spiffe/v2 v2.1.1
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2
github.com/testcontainers/testcontainers-go v0.27.0
github.com/testcontainers/testcontainers-go v0.30.0
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0
github.com/tetratelabs/wazero v1.5.0
github.com/tidwall/gjson v1.17.0
github.com/traefik/grpc-web v0.16.0
@ -79,18 +80,18 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/mod v0.14.0
golang.org/x/net v0.20.0
golang.org/x/sys v0.17.0
golang.org/x/mod v0.17.0
golang.org/x/net v0.24.0
golang.org/x/sys v0.19.0
golang.org/x/text v0.14.0
golang.org/x/time v0.5.0
golang.org/x/tools v0.17.0
golang.org/x/tools v0.20.0
google.golang.org/grpc v1.61.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.28.4
k8s.io/api v0.29.2
k8s.io/apiextensions-apiserver v0.28.3
k8s.io/apimachinery v0.28.4
k8s.io/client-go v0.28.4
k8s.io/apimachinery v0.29.2
k8s.io/client-go v0.29.2
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
mvdan.cc/xurls/v2 v2.5.0
sigs.k8s.io/controller-runtime v0.16.3
@ -151,7 +152,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/civo/civogo v0.3.11 // indirect
github.com/cloudflare/cloudflare-go v0.86.0 // indirect
github.com/containerd/containerd v1.7.11 // indirect
github.com/containerd/containerd v1.7.12 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
@ -161,14 +162,15 @@ require (
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/dnsimple/dnsimple-go v1.2.0 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.7.0 // indirect
github.com/exoscale/egoscale v0.102.3 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-errors/errors v1.0.1 // indirect
@ -176,6 +178,7 @@ require (
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.2.4 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
@ -196,7 +199,7 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gophercloud/gophercloud v1.0.0 // indirect
@ -244,11 +247,13 @@ require (
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
github.com/nrdcg/auroradns v1.1.0 // indirect
github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9 // indirect
@ -262,10 +267,9 @@ require (
github.com/nrdcg/porkbun v0.3.0 // indirect
github.com/nzdjb/go-metaname v1.0.0 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/onsi/ginkgo/v2 v2.17.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/opencontainers/runc v1.1.7 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
github.com/ovh/go-ovh v1.4.3 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
@ -276,7 +280,6 @@ require (
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/redis/go-redis/v9 v9.2.1 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/sacloud/api-client-go v0.2.8 // indirect
@ -284,7 +287,7 @@ require (
github.com/sacloud/iaas-api-go v1.11.1 // indirect
github.com/sacloud/packages-go v0.0.9 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 // indirect
github.com/shirou/gopsutil/v3 v3.23.11 // indirect
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
@ -292,7 +295,7 @@ require (
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect
github.com/tidwall/match v1.1.1 // indirect
@ -311,37 +314,39 @@ require (
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/contrib/propagators/aws v1.24.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.24.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0 // indirect
go.opentelemetry.io/contrib/propagators/ot v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.3.0 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.2.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/arch v0.4.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/term v0.19.0 // indirect
google.golang.org/api v0.149.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/protobuf v1.32.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/h2non/gock.v1 v1.0.16 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.7.13 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
nhooyr.io/websocket v1.8.7 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

136
go.sum
View file

@ -152,6 +152,7 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGz
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U=
github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -206,8 +207,8 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw=
github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE=
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd h1:0n+lFLh5zU0l6KSk3KpnDwfbPGAR44aRLgTbCnhRBHU=
@ -261,18 +262,18 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM=
github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U=
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/cli v24.0.9+incompatible h1:OxbimnP/z+qVjDLpq9wbeFU3Nc30XhSe+LkwYQisD50=
github.com/docker/cli v24.0.9+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@ -306,8 +307,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
@ -348,8 +349,9 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@ -496,8 +498,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@ -794,6 +796,8 @@ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -810,6 +814,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g=
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
github.com/natefinch/lumberjack v0.0.0-20201021141957-47ffae23317c h1:194MYKszq5DlJ73wpFuOTEsC/ryOOxt2F901D/07tec=
@ -860,23 +866,21 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
@ -961,10 +965,8 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg=
github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
@ -997,8 +999,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ=
github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
@ -1052,8 +1054,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -1064,9 +1066,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 h1:XGopsea1Dw7ecQ8JscCNQXDGYAKDiWjDeXnpN/+BY9g=
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@ -1076,8 +1078,10 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 h1:mmz2
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 h1:g9SWTaTy/rEuhMErC2jWq9Qt5ci+jBYSvXnJsLq4adg=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490/go.mod h1:l9q4vc1QiawUB1m3RU+87yLvrrxe54jc0w/kEl4DbSQ=
github.com/testcontainers/testcontainers-go v0.27.0 h1:IeIrJN4twonTDuMuBNQdKZ+K97yd7VrmNGu+lDpYcDk=
github.com/testcontainers/testcontainers-go v0.27.0/go.mod h1:+HgYZcd17GshBUZv9b+jKFJ198heWPQq3KQIp2+N+7U=
github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E=
github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0=
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0 h1:Mk47J0WcLoY2ig72lPl+/w8GTPYbRCdHoWcPjV2mVr8=
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0/go.mod h1:CNnA3717kbp5wRxz+gU/cAwX6+4+OOispIsjHmKsEWQ=
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
@ -1166,6 +1170,8 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/collector/pdata v1.2.0 h1:N6VdyEFYJyoHIKqHd0F372eNVD5b+AbH0ZQf7Z2jJ9I=
go.opentelemetry.io/collector/pdata v1.2.0/go.mod h1:mKXb6527Syb8PT4P9CZOJNbkuHOHjjGTZNNwSKESJhc=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/contrib/propagators/autoprop v0.49.0 h1:Jbr/9/jv1QpINge/fvJD4kUkW9/TqRNWU7H2GSK/Vb8=
go.opentelemetry.io/contrib/propagators/autoprop v0.49.0/go.mod h1:aZTdrjEnMOr6ODgjCQ955njFMLRDo1IJdTNS+agSPjA=
go.opentelemetry.io/contrib/propagators/aws v1.24.0 h1:cuwQmy9nGJi99fbwUfZSygCL3d347ddnSCWRuiVjhJ8=
@ -1205,12 +1211,14 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA=
@ -1218,6 +1226,7 @@ go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6m
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@ -1247,8 +1256,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1280,8 +1289,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1323,8 +1332,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1342,8 +1351,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1417,8 +1426,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -1427,8 +1436,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -1485,11 +1494,12 @@ golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4X
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1573,8 +1583,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -1629,16 +1639,16 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A=
k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0=
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8=
k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg=
k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA=
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
@ -1656,8 +1666,8 @@ sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs=
sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateway-role
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses
- gateways
- httproutes
- tcproutes
- tlsroutes
- referencegrants
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses/status
- gateways/status
- httproutes/status
- tcproutes/status
- tlsroutes/status
- referencegrants/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gateway-role
subjects:
- kind: ServiceAccount
name: traefik
namespace: traefik

View file

@ -0,0 +1,82 @@
---
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: traefik
spec:
controllerName: traefik.io/gateway-controller
---
kind: Namespace
apiVersion: v1
metadata:
name: traefik
---
kind: ServiceAccount
apiVersion: v1
metadata:
name: traefik
namespace: traefik
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: traefik
namespace: traefik
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik
containers:
- name: traefik
image: traefik/traefik:latest
imagePullPolicy: Never
args:
- --log.level=DEBUG
- --api.insecure
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --experimental.kubernetesgateway
- --providers.kubernetesgateway.experimentalChannel
- --providers.kubernetesgateway.statusaddress.service.namespace=traefik
- --providers.kubernetesgateway.statusaddress.service.name=traefik
ports:
- name: web
containerPort: 80
- name: admin
containerPort: 8080
- name: websecure
containerPort: 443
---
apiVersion: v1
kind: Service
metadata:
name: traefik
namespace: traefik
spec:
type: LoadBalancer
selector:
app: traefik
ports:
- port: 80
name: web
targetPort: web
- port: 443
name: websecure
targetPort: websecure
- port: 8080
name: admin
targetPort: admin

View file

@ -835,6 +835,10 @@ spec:
breaker will try to recover (as soon as it is in recovering
state).
x-kubernetes-int-or-string: true
responseCode:
description: ResponseCode is the status code that the circuit
breaker will return while it is in the open state.
type: integer
type: object
compress:
description: |-
@ -1331,7 +1335,7 @@ spec:
ipAllowList:
description: |-
IPAllowList holds the IP allowlist middleware configuration.
This middleware accepts / refuses requests based on the client IP.
This middleware limits allowed requests based on the client IP.
More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/
properties:
ipStrategy:
@ -1385,7 +1389,7 @@ spec:
type: object
sourceRange:
description: SourceRange defines the set of allowed IPs (or ranges
of allowed IPs by using CIDR notation).
of allowed IPs by using CIDR notation). Required.
items:
type: string
type: array

View file

@ -3,24 +3,27 @@ package integration
import (
"context"
"fmt"
"net"
"io"
"os"
"path/filepath"
"strings"
"slices"
"testing"
"time"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/k3s"
"github.com/testcontainers/testcontainers-go/network"
"github.com/traefik/traefik/v3/integration/try"
"github.com/traefik/traefik/v3/pkg/version"
"gopkg.in/yaml.v3"
ktypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
kclientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
klog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatev1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
@ -30,106 +33,146 @@ import (
ksuite "sigs.k8s.io/gateway-api/conformance/utils/suite"
)
const (
k3sImage = "docker.io/rancher/k3s:v1.29.3-k3s1"
traefikImage = "traefik/traefik:latest"
traefikDeployment = "deployments/traefik"
traefikNamespace = "traefik"
)
// K8sConformanceSuite tests suite.
type K8sConformanceSuite struct{ BaseSuite }
type K8sConformanceSuite struct {
BaseSuite
k3sContainer *k3s.K3sContainer
kubeClient client.Client
clientSet *kclientset.Clientset
}
func TestK8sConformanceSuite(t *testing.T) {
suite.Run(t, new(K8sConformanceSuite))
}
func (s *K8sConformanceSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("k8s")
s.composeUp()
abs, err := filepath.Abs("./fixtures/k8s/config.skip/kubeconfig.yaml")
require.NoError(s.T(), err)
err = try.Do(60*time.Second, func() error {
_, err := os.Stat(abs)
return err
})
require.NoError(s.T(), err)
data, err := os.ReadFile(abs)
require.NoError(s.T(), err)
content := strings.ReplaceAll(string(data), "https://server:6443", fmt.Sprintf("https://%s", net.JoinHostPort(s.getComposeServiceIP("server"), "6443")))
err = os.WriteFile(abs, []byte(content), 0o644)
require.NoError(s.T(), err)
err = os.Setenv("KUBECONFIG", abs)
require.NoError(s.T(), err)
}
func (s *K8sConformanceSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
generatedFiles := []string{
"./fixtures/k8s/config.skip/kubeconfig.yaml",
"./fixtures/k8s/config.skip/k3s.log",
"./fixtures/k8s/rolebindings.yaml",
"./fixtures/k8s/ccm.yaml",
}
for _, filename := range generatedFiles {
if err := os.Remove(filename); err != nil {
log.Warn().Err(err).Send()
}
}
}
func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
if !*k8sConformance {
s.T().Skip("Skip because it can take a long time to execute. To enable pass the `k8sConformance` flag.")
}
configFromFlags, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
s.BaseSuite.SetupSuite()
// Avoid panic.
klog.SetLogger(zap.New())
provider, err := testcontainers.ProviderDocker.GetProvider()
if err != nil {
s.T().Fatal(err)
}
kClient, err := client.New(configFromFlags, client.Options{})
ctx := context.Background()
// Ensure image is available locally.
images, err := provider.ListImages(ctx)
if err != nil {
s.T().Fatal(err)
}
if !slices.ContainsFunc(images, func(img testcontainers.ImageInfo) bool {
return img.Name == traefikImage
}) {
s.T().Fatal("Traefik image is not present")
}
s.k3sContainer, err = k3s.RunContainer(ctx,
testcontainers.WithImage(k3sImage),
k3s.WithManifest("./fixtures/k8s-conformance/00-experimental-v1.0.0.yml"),
k3s.WithManifest("./fixtures/k8s-conformance/01-rbac.yml"),
k3s.WithManifest("./fixtures/k8s-conformance/02-traefik.yml"),
network.WithNetwork(nil, s.network),
)
if err != nil {
s.T().Fatal(err)
}
if err = s.k3sContainer.LoadImages(ctx, traefikImage); err != nil {
s.T().Fatal(err)
}
exitCode, _, err := s.k3sContainer.Exec(ctx, []string{"kubectl", "wait", "-n", traefikNamespace, traefikDeployment, "--for=condition=Available", "--timeout=30s"})
if err != nil || exitCode > 0 {
s.T().Fatalf("Traefik pod is not ready: %v", err)
}
kubeConfigYaml, err := s.k3sContainer.GetKubeConfig(ctx)
if err != nil {
s.T().Fatal(err)
}
restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeConfigYaml)
if err != nil {
s.T().Fatalf("Error loading Kubernetes config: %v", err)
}
s.kubeClient, err = client.New(restConfig, client.Options{})
if err != nil {
s.T().Fatalf("Error initializing Kubernetes client: %v", err)
}
kClientSet, err := kclientset.NewForConfig(configFromFlags)
s.clientSet, err = kclientset.NewForConfig(restConfig)
if err != nil {
s.T().Fatalf("Error initializing Kubernetes REST client: %v", err)
}
if err = gatev1alpha2.AddToScheme(s.kubeClient.Scheme()); err != nil {
s.T().Fatal(err)
}
err = gatev1alpha2.AddToScheme(kClient.Scheme())
require.NoError(s.T(), err)
err = gatev1beta1.AddToScheme(kClient.Scheme())
require.NoError(s.T(), err)
err = gatev1.AddToScheme(kClient.Scheme())
require.NoError(s.T(), err)
s.traefikCmd(withConfigFile("fixtures/k8s_gateway_conformance.toml"))
// Wait for traefik to start
err = try.GetRequest("http://127.0.0.1:8080/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`))
require.NoError(s.T(), err)
err = try.Do(10*time.Second, func() error {
gwc := &gatev1.GatewayClass{}
err := kClient.Get(context.Background(), ktypes.NamespacedName{Name: "my-gateway-class"}, gwc)
if err != nil {
return fmt.Errorf("error fetching GatewayClass: %w", err)
if err = gatev1beta1.AddToScheme(s.kubeClient.Scheme()); err != nil {
s.T().Fatal(err)
}
return nil
})
if err = gatev1.AddToScheme(s.kubeClient.Scheme()); err != nil {
s.T().Fatal(err)
}
}
func (s *K8sConformanceSuite) TearDownSuite() {
ctx := context.Background()
if s.T().Failed() || *showLog {
k3sLogs, err := s.k3sContainer.Logs(ctx)
if err == nil {
if res, err := io.ReadAll(k3sLogs); err == nil {
s.T().Log(string(res))
}
}
exitCode, result, err := s.k3sContainer.Exec(ctx, []string{"kubectl", "logs", "-n", traefikNamespace, traefikDeployment})
if err == nil || exitCode == 0 {
if res, err := io.ReadAll(result); err == nil {
s.T().Log(string(res))
}
}
}
if err := s.k3sContainer.Terminate(ctx); err != nil {
s.T().Fatal(err)
}
s.BaseSuite.TearDownSuite()
}
func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
// Wait for traefik to start
k3sContainerIP, err := s.k3sContainer.ContainerIP(context.Background())
require.NoError(s.T(), err)
err = try.GetRequest("http://"+k3sContainerIP+":8080/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`))
require.NoError(s.T(), err)
opts := ksuite.Options{
Client: kClient,
RestConfig: configFromFlags,
Clientset: kClientSet,
GatewayClassName: "my-gateway-class",
Client: s.kubeClient,
Clientset: s.clientSet,
GatewayClassName: "traefik",
Debug: true,
CleanupBaseResources: true,
TimeoutConfig: config.TimeoutConfig{

View file

@ -207,7 +207,13 @@ func clean(element any) {
var svcFieldNames []string
for i := range valueSvcRoot.NumField() {
svcFieldNames = append(svcFieldNames, valueSvcRoot.Type().Field(i).Name)
field := valueSvcRoot.Type().Field(i)
// do not create empty node for hidden config.
if field.Tag.Get("file") == "-" && field.Tag.Get("kv") == "-" && field.Tag.Get("label") == "-" {
continue
}
svcFieldNames = append(svcFieldNames, field.Name)
}
sort.Strings(svcFieldNames)

View file

@ -39,6 +39,9 @@ type Middleware struct {
GrpcWeb *GrpcWeb `json:"grpcWeb,omitempty" toml:"grpcWeb,omitempty" yaml:"grpcWeb,omitempty" export:"true"`
Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty" export:"true"`
// Gateway API HTTPRoute filters middlewares.
RequestHeaderModifier *RequestHeaderModifier `json:"requestHeaderModifier,omitempty" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -420,11 +423,11 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
// +k8s:deepcopy-gen=true
// IPWhiteList holds the IP whitelist middleware configuration.
// This middleware accepts / refuses requests based on the client IP.
// This middleware limits allowed requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipwhitelist/
// Deprecated: please use IPAllowList instead.
type IPWhiteList struct {
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation).
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). Required.
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
}
@ -432,7 +435,7 @@ type IPWhiteList struct {
// +k8s:deepcopy-gen=true
// IPAllowList holds the IP allowlist middleware configuration.
// This middleware accepts / refuses requests based on the client IP.
// This middleware limits allowed requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/
type IPAllowList struct {
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation).
@ -673,3 +676,12 @@ type TLSClientCertificateSubjectDNInfo struct {
// Users holds a list of users.
type Users []string
// +k8s:deepcopy-gen=true
// RequestHeaderModifier holds the request header modifier configuration.
type RequestHeaderModifier struct {
Set map[string]string `json:"set,omitempty"`
Add map[string]string `json:"add,omitempty"`
Remove []string `json:"remove,omitempty"`
}

View file

@ -34,6 +34,8 @@ type TCPIPWhiteList struct {
// +k8s:deepcopy-gen=true
// TCPIPAllowList holds the TCP IPAllowList middleware configuration.
// This middleware limits allowed requests based on the client IP.
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/tcp/ipallowlist/
type TCPIPAllowList struct {
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`

View file

@ -859,6 +859,11 @@ func (in *Middleware) DeepCopyInto(out *Middleware) {
(*out)[key] = *val.DeepCopy()
}
}
if in.RequestHeaderModifier != nil {
in, out := &in.RequestHeaderModifier, &out.RequestHeaderModifier
*out = new(RequestHeaderModifier)
(*in).DeepCopyInto(*out)
}
return
}
@ -1067,6 +1072,41 @@ func (in *ReplacePathRegex) DeepCopy() *ReplacePathRegex {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RequestHeaderModifier) DeepCopyInto(out *RequestHeaderModifier) {
*out = *in
if in.Set != nil {
in, out := &in.Set, &out.Set
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Add != nil {
in, out := &in.Add, &out.Add
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Remove != nil {
in, out := &in.Remove, &out.Remove
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestHeaderModifier.
func (in *RequestHeaderModifier) DeepCopy() *RequestHeaderModifier {
if in == nil {
return nil
}
out := new(RequestHeaderModifier)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResponseForwarding) DeepCopyInto(out *ResponseForwarding) {
*out = *in

View file

@ -42,6 +42,9 @@ const (
// DefaultIdleTimeout before closing an idle connection.
DefaultIdleTimeout = 180 * time.Second
// DefaultReadTimeout defines the default maximum duration for reading the entire request, including the body.
DefaultReadTimeout = 60 * time.Second
// DefaultAcmeCAServer is the default ACME API endpoint.
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
@ -164,6 +167,7 @@ type RespondingTimeouts struct {
// SetDefaults sets the default values.
func (a *RespondingTimeouts) SetDefaults() {
a.ReadTimeout = ptypes.Duration(DefaultReadTimeout)
a.IdleTimeout = ptypes.Duration(DefaultIdleTimeout)
}

View file

@ -0,0 +1,56 @@
package headermodifier
import (
"context"
"net/http"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
)
const typeName = "RequestHeaderModifier"
// requestHeaderModifier is a middleware used to modify the headers of an HTTP request.
type requestHeaderModifier struct {
next http.Handler
name string
set map[string]string
add map[string]string
remove []string
}
// NewRequestHeaderModifier creates a new request header modifier middleware.
func NewRequestHeaderModifier(ctx context.Context, next http.Handler, config dynamic.RequestHeaderModifier, name string) (http.Handler, error) {
logger := middlewares.GetLogger(ctx, name, typeName)
logger.Debug().Msg("Creating middleware")
return &requestHeaderModifier{
next: next,
name: name,
set: config.Set,
add: config.Add,
remove: config.Remove,
}, nil
}
func (r *requestHeaderModifier) GetTracingInformation() (string, string, trace.SpanKind) {
return r.name, typeName, trace.SpanKindUnspecified
}
func (r *requestHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
for headerName, headerValue := range r.set {
req.Header.Set(headerName, headerValue)
}
for headerName, headerValue := range r.add {
req.Header.Add(headerName, headerValue)
}
for _, headerName := range r.remove {
req.Header.Del(headerName)
}
r.next.ServeHTTP(rw, req)
}

View file

@ -0,0 +1,121 @@
package headermodifier
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/testhelpers"
)
func TestRequestHeaderModifier(t *testing.T) {
testCases := []struct {
desc string
config dynamic.RequestHeaderModifier
requestHeaders http.Header
expectedHeaders http.Header
}{
{
desc: "no config",
config: dynamic.RequestHeaderModifier{},
expectedHeaders: map[string][]string{},
},
{
desc: "set header",
config: dynamic.RequestHeaderModifier{
Set: map[string]string{"Foo": "Bar"},
},
expectedHeaders: map[string][]string{"Foo": {"Bar"}},
},
{
desc: "set header with existing headers",
config: dynamic.RequestHeaderModifier{
Set: map[string]string{"Foo": "Bar"},
},
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foo"}},
expectedHeaders: map[string][]string{"Foo": {"Bar"}, "Bar": {"Foo"}},
},
{
desc: "set multiple headers with existing headers",
config: dynamic.RequestHeaderModifier{
Set: map[string]string{"Foo": "Bar", "Bar": "Foo"},
},
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foobar"}},
expectedHeaders: map[string][]string{"Foo": {"Bar"}, "Bar": {"Foo"}},
},
{
desc: "add header",
config: dynamic.RequestHeaderModifier{
Add: map[string]string{"Foo": "Bar"},
},
expectedHeaders: map[string][]string{"Foo": {"Bar"}},
},
{
desc: "add header with existing headers",
config: dynamic.RequestHeaderModifier{
Add: map[string]string{"Foo": "Bar"},
},
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foo"}},
expectedHeaders: map[string][]string{"Foo": {"Baz", "Bar"}, "Bar": {"Foo"}},
},
{
desc: "add multiple headers with existing headers",
config: dynamic.RequestHeaderModifier{
Add: map[string]string{"Foo": "Bar", "Bar": "Foo"},
},
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foobar"}},
expectedHeaders: map[string][]string{"Foo": {"Baz", "Bar"}, "Bar": {"Foobar", "Foo"}},
},
{
desc: "remove header",
config: dynamic.RequestHeaderModifier{
Remove: []string{"Foo"},
},
expectedHeaders: map[string][]string{},
},
{
desc: "remove header with existing headers",
config: dynamic.RequestHeaderModifier{
Remove: []string{"Foo"},
},
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foo"}},
expectedHeaders: map[string][]string{"Bar": {"Foo"}},
},
{
desc: "remove multiple headers with existing headers",
config: dynamic.RequestHeaderModifier{
Remove: []string{"Foo", "Bar"},
},
requestHeaders: map[string][]string{"Foo": {"Bar"}, "Bar": {"Foo"}, "Baz": {"Bar"}},
expectedHeaders: map[string][]string{"Baz": {"Bar"}},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
var gotHeaders http.Header
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotHeaders = r.Header
})
handler, err := NewRequestHeaderModifier(context.Background(), next, test.config, "foo-request-header-modifier")
require.NoError(t, err)
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
if test.requestHeaders != nil {
req.Header = test.requestHeaders
}
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, test.expectedHeaders, gotHeaders)
})
}
}

View file

@ -141,7 +141,7 @@ func newMiddlewareBuilder(ctx context.Context, goPath string, manifest *Manifest
case runtimeYaegi, "":
i, err := newInterpreter(ctx, goPath, manifest.Import)
if err != nil {
return nil, fmt.Errorf("failed to craete Yaegi intepreter: %w", err)
return nil, fmt.Errorf("failed to create Yaegi interpreter: %w", err)
}
return newYaegiMiddlewareBuilder(i, manifest.BasePkg, manifest.Import)

View file

@ -11,14 +11,15 @@ import (
// CheckFile checks file permissions and content size.
func CheckFile(name string) (bool, error) {
f, err := os.Open(name)
if err != nil {
if os.IsNotExist(err) {
f, err = os.Create(name)
if err != nil && os.IsNotExist(err) {
nf, err := os.Create(name)
if err != nil {
return false, err
}
return false, f.Chmod(0o600)
defer nf.Close()
return false, nf.Chmod(0o600)
}
if err != nil {
return false, err
}
defer f.Close()

View file

@ -135,7 +135,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
case event := <-eventsc:
if event.Action == "start" ||
event.Action == "die" ||
strings.HasPrefix(event.Action, "health_status") {
strings.HasPrefix(string(event.Action), "health_status") {
startStopHandle(event)
}
case err := <-errc:

View file

@ -319,7 +319,7 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
}
var mach *machine
if len(task.Attachments) != 0 {
if aws.StringValue(taskDef.NetworkMode) == "awsvpc" && len(task.Attachments) != 0 {
if len(container.NetworkInterfaces) == 0 {
logger.Error().Msgf("Skip container %s: no network interfaces", aws.StringValue(container.Name))
continue

View file

@ -645,6 +645,10 @@ func createCircuitBreakerMiddleware(circuitBreaker *traefikv1alpha1.CircuitBreak
}
}
if circuitBreaker.ResponseCode != 0 {
cb.ResponseCode = circuitBreaker.ResponseCode
}
return cb, nil
}

View file

@ -88,6 +88,8 @@ type CircuitBreaker struct {
FallbackDuration *intstr.IntOrString `json:"fallbackDuration,omitempty" toml:"fallbackDuration,omitempty" yaml:"fallbackDuration,omitempty" export:"true"`
// RecoveryDuration is the duration for which the circuit breaker will try to recover (as soon as it is in recovering state).
RecoveryDuration *intstr.IntOrString `json:"recoveryDuration,omitempty" toml:"recoveryDuration,omitempty" yaml:"recoveryDuration,omitempty" export:"true"`
// ResponseCode is the status code that the circuit breaker will return while it is in the open state.
ResponseCode int `json:"responseCode,omitempty" toml:"responseCode,omitempty" yaml:"responseCode,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true

View file

@ -0,0 +1,58 @@
---
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway-class
spec:
controllerName: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- name: http
protocol: HTTP
port: 80
allowedRoutes:
kinds:
- kind: HTTPRoute
group: gateway.networking.k8s.io
namespaces:
from: Same
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: http-app-1
namespace: default
spec:
parentRefs:
- name: my-gateway
kind: Gateway
group: gateway.networking.k8s.io
hostnames:
- "example.org"
rules:
- backendRefs:
- name: whoami
port: 80
weight: 1
kind: Service
group: ""
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Foo
value: Bar
add:
- name: X-Bar
value: Foo
remove:
- X-Baz

View file

@ -269,3 +269,16 @@ spec:
- protocol: TCP
port: 10000
name: tcp-2
---
apiVersion: v1
kind: Service
metadata:
name: status-address
namespace: default
status:
loadBalancer:
ingress:
- hostname: foo.bar
- ip: 1.2.3.4

View file

@ -58,6 +58,7 @@ type Provider struct {
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
ThrottleDuration ptypes.Duration `description:"Kubernetes refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
ExperimentalChannel bool `description:"Toggles Experimental Channel resources support (TCPRoute, TLSRoute...)." json:"experimentalChannel,omitempty" toml:"experimentalChannel,omitempty" yaml:"experimentalChannel,omitempty" export:"true"`
StatusAddress *StatusAddress `description:"Defines the Kubernetes Gateway status address." json:"statusAddress,omitempty" toml:"statusAddress,omitempty" yaml:"statusAddress,omitempty" export:"true"`
EntryPoints map[string]Entrypoint `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
@ -71,6 +72,19 @@ type Provider struct {
routerTransform k8s.RouterTransform
}
// StatusAddress holds the Gateway Status address configuration.
type StatusAddress struct {
IP string `description:"IP used to set Kubernetes Gateway status address." json:"ip,omitempty" toml:"ip,omitempty" yaml:"ip,omitempty"`
Hostname string `description:"Hostname used for Kubernetes Gateway status address." json:"hostname,omitempty" toml:"hostname,omitempty" yaml:"hostname,omitempty"`
Service ServiceRef `description:"Published Kubernetes Service to copy status addresses from." json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
}
// ServiceRef holds a Kubernetes service reference.
type ServiceRef struct {
Name string `description:"Name of the Kubernetes service." json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
Namespace string `description:"Namespace of the Kubernetes service." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
}
// BuildFilterFunc returns the name of the filter and the related dynamic.Middleware if needed.
type BuildFilterFunc func(name, namespace string) (string, *dynamic.Middleware, error)
@ -368,9 +382,14 @@ func (p *Provider) createGatewayConf(ctx context.Context, client Client, gateway
// and cannot be configured on the Gateway.
listenerStatuses := p.fillGatewayConf(ctx, client, gateway, conf, tlsConfigs)
gatewayStatus, errG := p.makeGatewayStatus(gateway, listenerStatuses)
addresses, err := p.gatewayAddresses(client)
if err != nil {
return nil, fmt.Errorf("get Gateway status addresses: %w", err)
}
err := client.UpdateGatewayStatus(gateway, gatewayStatus)
gatewayStatus, errG := p.makeGatewayStatus(gateway, listenerStatuses, addresses)
err = client.UpdateGatewayStatus(gateway, gatewayStatus)
if err != nil {
return nil, fmt.Errorf("an error occurred while updating gateway status: %w", err)
}
@ -618,11 +637,8 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *
return listenerStatuses
}
func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses []gatev1.ListenerStatus) (gatev1.GatewayStatus, error) {
// As Status.Addresses are not implemented yet, we initialize an empty array to follow the API expectations.
gatewayStatus := gatev1.GatewayStatus{
Addresses: []gatev1.GatewayStatusAddress{},
}
func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses []gatev1.ListenerStatus, addresses []gatev1.GatewayStatusAddress) (gatev1.GatewayStatus, error) {
gatewayStatus := gatev1.GatewayStatus{Addresses: addresses}
var result error
for i, listener := range listenerStatuses {
@ -701,6 +717,57 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses [
return gatewayStatus, nil
}
func (p *Provider) gatewayAddresses(client Client) ([]gatev1.GatewayStatusAddress, error) {
if p.StatusAddress == nil {
return nil, nil
}
if p.StatusAddress.IP != "" {
return []gatev1.GatewayStatusAddress{{
Type: ptr.To(gatev1.IPAddressType),
Value: p.StatusAddress.IP,
}}, nil
}
if p.StatusAddress.Hostname != "" {
return []gatev1.GatewayStatusAddress{{
Type: ptr.To(gatev1.HostnameAddressType),
Value: p.StatusAddress.Hostname,
}}, nil
}
svcRef := p.StatusAddress.Service
if svcRef.Name != "" && svcRef.Namespace != "" {
svc, exists, err := client.GetService(svcRef.Namespace, svcRef.Name)
if err != nil {
return nil, fmt.Errorf("unable to get service: %w", err)
}
if !exists {
return nil, fmt.Errorf("could not find a service with name %s in namespace %s", svcRef.Name, svcRef.Namespace)
}
var addresses []gatev1.GatewayStatusAddress
for _, addr := range svc.Status.LoadBalancer.Ingress {
switch {
case addr.IP != "":
addresses = append(addresses, gatev1.GatewayStatusAddress{
Type: ptr.To(gatev1.IPAddressType),
Value: addr.IP,
})
case addr.Hostname != "":
addresses = append(addresses, gatev1.GatewayStatusAddress{
Type: ptr.To(gatev1.HostnameAddressType),
Value: addr.Hostname,
})
}
}
return addresses, nil
}
return nil, errors.New("empty Gateway status address configuration")
}
func (p *Provider) entryPointName(port gatev1.PortNumber, protocol gatev1.ProtocolType) (string, error) {
portStr := strconv.FormatInt(int64(port), 10)
@ -1921,6 +1988,11 @@ func (p *Provider) loadMiddlewares(listener gatev1.Listener, namespace string, p
}
middlewares[name] = middleware
case gatev1.HTTPRouteFilterRequestHeaderModifier:
middlewareName := provider.Normalize(fmt.Sprintf("%s-%s-%d", prefix, strings.ToLower(string(filter.Type)), i))
middlewares[middlewareName] = createRequestHeaderModifier(filter.RequestHeaderModifier)
default:
// As per the spec:
// https://gateway-api.sigs.k8s.io/api-types/httproute/#filters-optional
@ -1950,6 +2022,28 @@ func (p *Provider) loadHTTPRouteFilterExtensionRef(namespace string, extensionRe
return filterFunc(string(extensionRef.Name), namespace)
}
// createRequestHeaderModifier does not enforce/check the configuration,
// as the spec indicates that either the webhook or CEL (since v1.0 GA Release) should enforce that.
func createRequestHeaderModifier(filter *gatev1.HTTPHeaderFilter) *dynamic.Middleware {
sets := map[string]string{}
for _, header := range filter.Set {
sets[string(header.Name)] = header.Value
}
adds := map[string]string{}
for _, header := range filter.Add {
adds[string(header.Name)] = header.Value
}
return &dynamic.Middleware{
RequestHeaderModifier: &dynamic.RequestHeaderModifier{
Set: sets,
Add: adds,
Remove: filter.Remove,
},
}
}
func createRedirectRegexMiddleware(scheme string, filter *gatev1.HTTPRequestRedirectFilter) (*dynamic.Middleware, error) {
// Use the HTTPRequestRedirectFilter scheme if defined.
filterScheme := scheme

View file

@ -1517,6 +1517,75 @@ func TestLoadHTTPRoutes(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, request header modifier",
paths: []string{"services.yml", "httproute/filter_request_header_modifier.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr",
Rule: "Host(`example.org`) && PathPrefix(`/`)",
RuleSyntax: "v3",
Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestheadermodifier-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestheadermodifier-0": {
RequestHeaderModifier: &dynamic.RequestHeaderModifier{
Set: map[string]string{"X-Foo": "Bar"},
Add: map[string]string{"X-Bar": "Foo"},
Remove: []string{"X-Baz"},
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, redirect HTTP to HTTPS",
paths: []string{"services.yml", "httproute/filter_http_to_https.yml"},
@ -6227,30 +6296,6 @@ func Test_makeListenerKey(t *testing.T) {
}
}
func hostnamePtr(hostname gatev1.Hostname) *gatev1.Hostname {
return &hostname
}
func groupPtr(group gatev1.Group) *gatev1.Group {
return &group
}
func sectionNamePtr(sectionName gatev1.SectionName) *gatev1.SectionName {
return &sectionName
}
func namespacePtr(namespace gatev1.Namespace) *gatev1.Namespace {
return &namespace
}
func kindPtr(kind gatev1.Kind) *gatev1.Kind {
return &kind
}
func pathMatchTypePtr(p gatev1.PathMatchType) *gatev1.PathMatchType { return &p }
func headerMatchTypePtr(h gatev1.HeaderMatchType) *gatev1.HeaderMatchType { return &h }
func Test_referenceGrantMatchesFrom(t *testing.T) {
testCases := []struct {
desc string
@ -6489,6 +6534,131 @@ func Test_referenceGrantMatchesTo(t *testing.T) {
}
}
func Test_gatewayAddresses(t *testing.T) {
testCases := []struct {
desc string
statusAddress *StatusAddress
paths []string
wantErr require.ErrorAssertionFunc
want []gatev1.GatewayStatusAddress
}{
{
desc: "nothing",
wantErr: require.NoError,
},
{
desc: "empty configuration",
statusAddress: &StatusAddress{},
wantErr: require.Error,
},
{
desc: "IP address",
statusAddress: &StatusAddress{
IP: "1.2.3.4",
},
wantErr: require.NoError,
want: []gatev1.GatewayStatusAddress{
{
Type: ptr.To(gatev1.IPAddressType),
Value: "1.2.3.4",
},
},
},
{
desc: "hostname address",
statusAddress: &StatusAddress{
Hostname: "foo.bar",
},
wantErr: require.NoError,
want: []gatev1.GatewayStatusAddress{
{
Type: ptr.To(gatev1.HostnameAddressType),
Value: "foo.bar",
},
},
},
{
desc: "service",
statusAddress: &StatusAddress{
Service: ServiceRef{
Name: "status-address",
Namespace: "default",
},
},
paths: []string{"services.yml"},
wantErr: require.NoError,
want: []gatev1.GatewayStatusAddress{
{
Type: ptr.To(gatev1.HostnameAddressType),
Value: "foo.bar",
},
{
Type: ptr.To(gatev1.IPAddressType),
Value: "1.2.3.4",
},
},
},
{
desc: "missing service",
statusAddress: &StatusAddress{
Service: ServiceRef{
Name: "status-address2",
Namespace: "default",
},
},
wantErr: require.Error,
},
{
desc: "service without load-balancer status",
statusAddress: &StatusAddress{
Service: ServiceRef{
Name: "whoamitcp-bar",
Namespace: "bar",
},
},
paths: []string{"services.yml"},
wantErr: require.NoError,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := Provider{StatusAddress: test.statusAddress}
got, err := p.gatewayAddresses(newClientMock(test.paths...))
test.wantErr(t, err)
assert.Equal(t, test.want, got)
})
}
}
func hostnamePtr(hostname gatev1.Hostname) *gatev1.Hostname {
return &hostname
}
func groupPtr(group gatev1.Group) *gatev1.Group {
return &group
}
func sectionNamePtr(sectionName gatev1.SectionName) *gatev1.SectionName {
return &sectionName
}
func namespacePtr(namespace gatev1.Namespace) *gatev1.Namespace {
return &namespace
}
func kindPtr(kind gatev1.Kind) *gatev1.Kind {
return &kind
}
func pathMatchTypePtr(p gatev1.PathMatchType) *gatev1.PathMatchType { return &p }
func headerMatchTypePtr(h gatev1.HeaderMatchType) *gatev1.HeaderMatchType { return &h }
func objectNamePtr(objectName gatev1.ObjectName) *gatev1.ObjectName {
return &objectName
}

View file

@ -97,10 +97,13 @@ func (p *Provider) buildTCPConfig(i item, configuration *dynamic.TCPConfiguratio
}
for _, service := range configuration.Services {
// Leave load balancer empty when no address and allowEmptyServices = true
if !(i.Address == "" && p.AllowEmptyServices) {
if err := p.addServerTCP(i, service.LoadBalancer); err != nil {
return err
}
}
}
return nil
}
@ -115,10 +118,13 @@ func (p *Provider) buildUDPConfig(i item, configuration *dynamic.UDPConfiguratio
}
for _, service := range configuration.Services {
// Leave load balancer empty when no address and allowEmptyServices = true
if !(i.Address == "" && p.AllowEmptyServices) {
if err := p.addServerUDP(i, service.LoadBalancer); err != nil {
return err
}
}
}
return nil
}
@ -136,10 +142,13 @@ func (p *Provider) buildServiceConfig(i item, configuration *dynamic.HTTPConfigu
}
for _, service := range configuration.Services {
// Leave load balancer empty when no address and allowEmptyServices = true
if !(i.Address == "" && p.AllowEmptyServices) {
if err := p.addServer(i, service.LoadBalancer); err != nil {
return err
}
}
}
return nil
}

View file

@ -706,6 +706,42 @@ func Test_buildConfig(t *testing.T) {
},
},
},
{
desc: "empty service",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.enable=true",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one service with rule label",
items: []item{
@ -2825,6 +2861,307 @@ func Test_buildConfig(t *testing.T) {
}
}
func Test_buildConfigAllowEmptyServicesTrue(t *testing.T) {
testCases := []struct {
desc string
items []item
constraints string
expected *dynamic.Configuration
}{
{
desc: "empty service http",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.enable=true",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Test",
Rule: "Host(`Test.traefik.test`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Test": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: nil,
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "empty service tcp",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.tcp.routers.test.rule = HostSNI(`foobar`)",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"test": {
Rule: "HostSNI(`foobar`)",
Service: "Test",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"Test": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "empty service udp",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.udp.routers.test.entrypoints = udp",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"test": {
EntryPoints: []string{"udp"},
Service: "Test",
},
},
Services: map[string]*dynamic.UDPService{
"Test": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
p := new(Provider)
p.SetDefaults()
p.AllowEmptyServices = true
p.DefaultRule = "Host(`{{ normalize .Name }}.traefik.test`)"
p.Constraints = test.constraints
err := p.Init()
require.NoError(t, err)
ctx := context.TODO()
c := p.buildConfig(ctx, test.items)
require.Equal(t, test.expected, c)
})
}
}
func Test_buildConfigAllowEmptyServicesFalseDefault(t *testing.T) {
testCases := []struct {
desc string
items []item
constraints string
expected *dynamic.Configuration
}{
{
desc: "empty service http",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.enable=true",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "empty service tcp",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.tcp.routers.test.rule = HostSNI(`foobar`)",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "empty service udp",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.udp.routers.test.entrypoints = udp",
},
Address: "",
Port: -1,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
p := new(Provider)
p.SetDefaults()
p.DefaultRule = "Host(`{{ normalize .Name }}.traefik.test`)"
p.Constraints = test.constraints
err := p.Init()
require.NoError(t, err)
ctx := context.TODO()
c := p.buildConfig(ctx, test.items)
require.Equal(t, test.expected, c)
})
}
}
func Test_keepItem(t *testing.T) {
testCases := []struct {
name string

View file

@ -0,0 +1,220 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job1",
"ParentID": "",
"Name": "job1",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "654cb8ee-9c81-4fe8-02a0-2aecdea35ae3",
"Type": "horizontal",
"Target": {
"Job": "job1",
"Group": "group1",
"Namespace": "default"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 0,
"ModifyIndex": 0
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"http"
]
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job1",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "running",
"StatusDescription": "",
"Stable": true,
"Version": 11,
"SubmitTime": 1705690395733241600,
"CreateIndex": 493,
"ModifyIndex": 9961,
"JobModifyIndex": 9955
}

View file

@ -0,0 +1,220 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job2",
"ParentID": "",
"Name": "job2",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 0,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "0ae1d8fa-aa84-0b1b-941f-82dc71bc4664",
"Type": "horizontal",
"Target": {
"Group": "group1",
"Namespace": "default",
"Job": "job2"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 9975,
"ModifyIndex": 9975
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"ports": [
"http"
],
"image": "nginx"
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job2",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "dead",
"StatusDescription": "",
"Stable": true,
"Version": 10,
"SubmitTime": 1705690880440177400,
"CreateIndex": 2923,
"ModifyIndex": 10048,
"JobModifyIndex": 10044
}

View file

@ -0,0 +1,206 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job3",
"ParentID": "",
"Name": "job3",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": null,
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"ports": [
"http"
],
"image": "nginx"
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job3",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "running",
"StatusDescription": "",
"Stable": true,
"Version": 4,
"SubmitTime": 1705690892484556300,
"CreateIndex": 2932,
"ModifyIndex": 9992,
"JobModifyIndex": 9983
}

View file

@ -0,0 +1,206 @@
{
"Stop": true,
"Region": "global",
"Namespace": "default",
"ID": "job4",
"ParentID": "",
"Name": "job4",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": null,
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"http"
]
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job4",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "dead",
"StatusDescription": "",
"Stable": true,
"Version": 11,
"SubmitTime": 1705690905317339000,
"CreateIndex": 3079,
"ModifyIndex": 10054,
"JobModifyIndex": 10052
}

View file

@ -0,0 +1,299 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job5",
"ParentID": "",
"Name": "job5",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "56d57f83-7b9e-fbfa-af96-e2c7f5dc698c",
"Type": "horizontal",
"Target": {
"Namespace": "default",
"Job": "job5",
"Group": "group1"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 0,
"ModifyIndex": 0
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"http"
]
},
"Env": null,
"Services": [
{
"Name": "job5task1",
"TaskName": "task1",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
},
{
"Name": "task2",
"Driver": "docker",
"User": "",
"Config": {
"ports": [
"other"
],
"image": "nginx"
},
"Env": null,
"Services": [
{
"Name": "job5task2",
"TaskName": "task2",
"PortLabel": "other",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
},
{
"Label": "other",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": null,
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "running",
"StatusDescription": "",
"Stable": true,
"Version": 7,
"SubmitTime": 1705690918813110300,
"CreateIndex": 3095,
"ModifyIndex": 10018,
"JobModifyIndex": 10008
}

View file

@ -0,0 +1,299 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job6",
"ParentID": "",
"Name": "job6",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 0,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "d18b02ae-5a68-e635-8100-06b110910b5f",
"Type": "horizontal",
"Target": {
"Job": "job6",
"Group": "group1",
"Namespace": "default"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 10020,
"ModifyIndex": 10020
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"http"
]
},
"Env": null,
"Services": [
{
"Name": "job6task1",
"TaskName": "task1",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
},
{
"Name": "task2",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"other"
]
},
"Env": null,
"Services": [
{
"Name": "job6task2",
"TaskName": "task2",
"PortLabel": "other",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
},
{
"Label": "other",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": null,
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "dead",
"StatusDescription": "",
"Stable": true,
"Version": 3,
"SubmitTime": 1705690931854150700,
"CreateIndex": 9941,
"ModifyIndex": 10078,
"JobModifyIndex": 10074
}

View file

@ -0,0 +1,222 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job7",
"ParentID": "",
"Name": "job7",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "e3b82307-1b7f-5fc6-901a-d9174418461f",
"Type": "horizontal",
"Target": {
"Namespace": "default",
"Job": "job7",
"Group": "group1"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 0,
"ModifyIndex": 0
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"http"
]
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job7",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true",
"traefik.tcp.routers.job7.rule=HostSNI(`job7`)",
"traefik.tcp.routers.job7.tls.passthrough=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "running",
"StatusDescription": "",
"Stable": true,
"Version": 1,
"SubmitTime": 1705752438438572000,
"CreateIndex": 11221,
"ModifyIndex": 11238,
"JobModifyIndex": 11232
}

View file

@ -0,0 +1,221 @@
{
"Stop": false,
"Region": "global",
"Namespace": "default",
"ID": "job8",
"ParentID": "",
"Name": "job8",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "3828aaa9-4e16-cde5-cc80-f0cec4a7c82d",
"Type": "horizontal",
"Target": {
"Namespace": "default",
"Job": "job8",
"Group": "group1"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 0,
"ModifyIndex": 0
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"ports": [
"http"
],
"image": "nginx"
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job8",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true",
"traefik.udp.routers.job8.service=job8"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "running",
"StatusDescription": "",
"Stable": true,
"Version": 2,
"SubmitTime": 1705753285493029600,
"CreateIndex": 11276,
"ModifyIndex": 11303,
"JobModifyIndex": 11297
}

View file

@ -0,0 +1,220 @@
{
"Stop": true,
"Region": "global",
"Namespace": "default",
"ID": "job9",
"ParentID": "",
"Name": "job9",
"Type": "service",
"Priority": 50,
"AllAtOnce": false,
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Constraints": null,
"Affinities": null,
"Spreads": null,
"TaskGroups": [
{
"Name": "group1",
"Count": 1,
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000,
"ProgressDeadline": 600000000000,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Migrate": {
"MaxParallel": 1,
"HealthCheck": "checks",
"MinHealthyTime": 10000000000,
"HealthyDeadline": 300000000000
},
"Constraints": [
{
"LTarget": "${attr.nomad.service_discovery}",
"RTarget": "true",
"Operand": "="
}
],
"Scaling": {
"ID": "094d38a7-24cf-d3a4-3a82-cfc50ef7c597",
"Type": "horizontal",
"Target": {
"Group": "group1",
"Namespace": "default",
"Job": "job9"
},
"Policy": null,
"Min": 0,
"Max": 3,
"Enabled": true,
"CreateIndex": 0,
"ModifyIndex": 0
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"Tasks": [
{
"Name": "task1",
"Driver": "docker",
"User": "",
"Config": {
"image": "nginx",
"ports": [
"http"
]
},
"Env": null,
"Services": null,
"Vault": null,
"Templates": null,
"Constraints": null,
"Affinities": null,
"Resources": {
"CPU": 100,
"Cores": 0,
"MemoryMB": 300,
"MemoryMaxMB": 0,
"DiskMB": 0,
"IOPS": 0,
"Networks": null,
"Devices": null
},
"RestartPolicy": {
"Attempts": 2,
"Interval": 1800000000000,
"Delay": 15000000000,
"Mode": "fail",
"RenderTemplates": false
},
"DispatchPayload": null,
"Lifecycle": null,
"Meta": null,
"KillTimeout": 5000000000,
"LogConfig": {
"MaxFiles": 10,
"MaxFileSizeMB": 10,
"Disabled": false
},
"Artifacts": null,
"Leader": false,
"ShutdownDelay": 0,
"VolumeMounts": null,
"ScalingPolicies": null,
"KillSignal": "",
"Kind": "",
"CSIPluginConfig": null,
"Identity": null
}
],
"EphemeralDisk": {
"Sticky": false,
"SizeMB": 300,
"Migrate": false
},
"Meta": null,
"ReschedulePolicy": {
"Attempts": 0,
"Interval": 0,
"Delay": 30000000000,
"DelayFunction": "exponential",
"MaxDelay": 3600000000000,
"Unlimited": true
},
"Affinities": null,
"Spreads": null,
"Networks": [
{
"Mode": "",
"Device": "",
"CIDR": "",
"IP": "",
"Hostname": "",
"MBits": 0,
"DNS": null,
"ReservedPorts": null,
"DynamicPorts": [
{
"Label": "http",
"Value": 0,
"To": 80,
"HostNetwork": "default"
}
]
}
],
"Consul": {
"Namespace": ""
},
"Services": [
{
"Name": "job9",
"TaskName": "",
"PortLabel": "http",
"AddressMode": "auto",
"Address": "",
"EnableTagOverride": false,
"Tags": [
"traefik.enable=true"
],
"CanaryTags": null,
"Checks": null,
"Connect": null,
"Meta": null,
"CanaryMeta": null,
"TaggedAddresses": null,
"Namespace": "default",
"OnUpdate": "require_healthy",
"Provider": "nomad"
}
],
"Volumes": null,
"ShutdownDelay": null,
"StopAfterClientDisconnect": null,
"MaxClientDisconnect": null
}
],
"Update": {
"Stagger": 30000000000,
"MaxParallel": 1,
"HealthCheck": "",
"MinHealthyTime": 0,
"HealthyDeadline": 0,
"ProgressDeadline": 0,
"AutoRevert": false,
"AutoPromote": false,
"Canary": 0
},
"Multiregion": null,
"Periodic": null,
"ParameterizedJob": null,
"Dispatched": false,
"DispatchIdempotencyToken": "",
"Payload": null,
"Meta": null,
"ConsulToken": "",
"ConsulNamespace": "",
"VaultToken": "",
"VaultNamespace": "",
"NomadTokenID": "",
"Status": "dead",
"StatusDescription": "",
"Stable": true,
"Version": 3,
"SubmitTime": 1705753979676559600,
"CreateIndex": 11317,
"ModifyIndex": 11346,
"JobModifyIndex": 11344
}

View file

@ -0,0 +1,56 @@
[
{
"ID": "job1",
"ParentID": "",
"Name": "job1",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "running",
"StatusDescription": "",
"JobSummary": {
"JobID": "job1",
"Namespace": "default",
"Summary": {
"job1": {
"Queued": 0,
"Complete": 1,
"Failed": 0,
"Running": 0,
"Starting": 0,
"Lost": 0,
"Unknown": 0
},
"group1": {
"Queued": 0,
"Complete": 6,
"Failed": 1,
"Running": 1,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 493,
"ModifyIndex": 9909
},
"CreateIndex": 493,
"ModifyIndex": 9961,
"JobModifyIndex": 9955,
"SubmitTime": 1705690395733241600,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job2",
"ParentID": "",
"Name": "job2",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "dead",
"StatusDescription": "",
"JobSummary": {
"JobID": "job2",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 6,
"Failed": 6,
"Running": 0,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 2923,
"ModifyIndex": 10051
},
"CreateIndex": 2923,
"ModifyIndex": 10048,
"JobModifyIndex": 10044,
"SubmitTime": 1705690880440177400,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job3",
"ParentID": "",
"Name": "job3",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "running",
"StatusDescription": "",
"JobSummary": {
"JobID": "job3",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 1,
"Failed": 0,
"Running": 1,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 2932,
"ModifyIndex": 9989
},
"CreateIndex": 2932,
"ModifyIndex": 9992,
"JobModifyIndex": 9983,
"SubmitTime": 1705690892484556300,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job4",
"ParentID": "",
"Name": "job4",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": true,
"Status": "dead",
"StatusDescription": "",
"JobSummary": {
"JobID": "job4",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 6,
"Failed": 0,
"Running": 0,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 3079,
"ModifyIndex": 10057
},
"CreateIndex": 3079,
"ModifyIndex": 10054,
"JobModifyIndex": 10052,
"SubmitTime": 1705690905317339000,
"Meta": null
}
]

View file

@ -0,0 +1,56 @@
[
{
"ID": "job5",
"ParentID": "",
"Name": "job5",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "running",
"StatusDescription": "",
"JobSummary": {
"JobID": "job5",
"Namespace": "default",
"Summary": {
"job5": {
"Queued": 0,
"Complete": 2,
"Failed": 0,
"Running": 0,
"Starting": 0,
"Lost": 0,
"Unknown": 0
},
"group1": {
"Queued": 0,
"Complete": 4,
"Failed": 0,
"Running": 1,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 3095,
"ModifyIndex": 10015
},
"CreateIndex": 3095,
"ModifyIndex": 10018,
"JobModifyIndex": 10008,
"SubmitTime": 1705690918813110300,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job6",
"ParentID": "",
"Name": "job6",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "dead",
"StatusDescription": "",
"JobSummary": {
"JobID": "job6",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 3,
"Failed": 0,
"Running": 0,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 9941,
"ModifyIndex": 10082
},
"CreateIndex": 9941,
"ModifyIndex": 10078,
"JobModifyIndex": 10074,
"SubmitTime": 1705690931854150700,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job7",
"ParentID": "",
"Name": "job7",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "running",
"StatusDescription": "",
"JobSummary": {
"JobID": "job7",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 0,
"Failed": 0,
"Running": 1,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 11221,
"ModifyIndex": 11225
},
"CreateIndex": 11221,
"ModifyIndex": 11238,
"JobModifyIndex": 11232,
"SubmitTime": 1705752438438572000,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job8",
"ParentID": "",
"Name": "job8",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": false,
"Status": "running",
"StatusDescription": "",
"JobSummary": {
"JobID": "job8",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 0,
"Failed": 0,
"Running": 1,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 11276,
"ModifyIndex": 11281
},
"CreateIndex": 11276,
"ModifyIndex": 11303,
"JobModifyIndex": 11297,
"SubmitTime": 1705753285493029600,
"Meta": null
}
]

View file

@ -0,0 +1,47 @@
[
{
"ID": "job9",
"ParentID": "",
"Name": "job9",
"Namespace": "default",
"Datacenters": [
"dc1"
],
"NodePool": "default",
"Multiregion": null,
"Type": "service",
"Priority": 50,
"Periodic": false,
"ParameterizedJob": false,
"Stop": true,
"Status": "dead",
"StatusDescription": "",
"JobSummary": {
"JobID": "job9",
"Namespace": "default",
"Summary": {
"group1": {
"Queued": 0,
"Complete": 1,
"Failed": 0,
"Running": 0,
"Starting": 0,
"Lost": 0,
"Unknown": 0
}
},
"Children": {
"Pending": 0,
"Running": 0,
"Dead": 0
},
"CreateIndex": 11317,
"ModifyIndex": 11349
},
"CreateIndex": 11317,
"ModifyIndex": 11346,
"JobModifyIndex": 11344,
"SubmitTime": 1705753979676559600,
"Meta": null
}
]

View file

@ -0,0 +1,20 @@
[
{
"Address": "127.0.0.1",
"AllocID": "71a63a80-a98a-93ee-4fd7-73b808577c20",
"CreateIndex": 18,
"Datacenter": "dc1",
"ID": "_nomad-task-71a63a80-a98a-93ee-4fd7-73b808577c20-group-hello-nomad-hello-nomad-http",
"JobID": "echo",
"ModifyIndex": 18,
"Namespace": "default",
"NodeID": "6d7f412e-e7ff-2e66-d47b-867b0e9d8726",
"Port": 20627,
"ServiceName": "hello-nomad",
"Tags": [
"traefik.enable=true",
"traefik.http.routers.hellon.entrypoints=web",
"traefik.http.routers.hellon.service=hello-nomad"
]
}
]

View file

@ -0,0 +1,18 @@
[
{
"ID": "_nomad-task-03c7270c-f475-5981-1932-87c0a8a5aa24-group-group1-job1-http",
"ServiceName": "job1",
"Namespace": "default",
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
"Datacenter": "dc1",
"JobID": "job1",
"AllocID": "03c7270c-f475-5981-1932-87c0a8a5aa24",
"Tags": [
"traefik.enable=true"
],
"Address": "192.168.1.21",
"Port": 29916,
"CreateIndex": 5753,
"ModifyIndex": 9958
}
]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,18 @@
[
{
"ID": "_nomad-task-dd945b55-70fa-0efc-6512-b88fb55ce33f-group-group1-job3-http",
"ServiceName": "job3",
"Namespace": "default",
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
"Datacenter": "dc1",
"JobID": "job3",
"AllocID": "dd945b55-70fa-0efc-6512-b88fb55ce33f",
"Tags": [
"traefik.enable=true"
],
"Address": "192.168.1.21",
"Port": 29983,
"CreateIndex": 9987,
"ModifyIndex": 9987
}
]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,18 @@
[
{
"ID": "_nomad-task-a98bac3d-5382-3032-1954-57aff58b20c1-task1-job5task1-http",
"ServiceName": "job5task1",
"Namespace": "default",
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
"Datacenter": "dc1",
"JobID": "job5",
"AllocID": "a98bac3d-5382-3032-1954-57aff58b20c1",
"Tags": [
"traefik.enable=true"
],
"Address": "192.168.1.21",
"Port": 24542,
"CreateIndex": 10013,
"ModifyIndex": 10013
}
]

View file

@ -0,0 +1,18 @@
[
{
"ID": "_nomad-task-a98bac3d-5382-3032-1954-57aff58b20c1-task2-job5task2-other",
"ServiceName": "job5task2",
"Namespace": "default",
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
"Datacenter": "dc1",
"JobID": "job5",
"AllocID": "a98bac3d-5382-3032-1954-57aff58b20c1",
"Tags": [
"traefik.enable=true"
],
"Address": "192.168.1.21",
"Port": 30165,
"CreateIndex": 10014,
"ModifyIndex": 10014
}
]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

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