Migrate to github.com/moby/moby modules

This commit is contained in:
Sebastiaan van Stijn 2026-05-04 15:50:05 +02:00 committed by GitHub
parent bd6a685be3
commit 8f99bbcfba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 480 additions and 439 deletions

View File

@ -9,6 +9,16 @@ This guide provides detailed migration steps for upgrading between different Tra
---
## v3.6.16
### Docker provider: minimum Docker Engine version
Starting with `v3.6.16`, the Docker provider requires Docker API version v1.40 or
above ([Docker Engine v19.03](https://docs.docker.com/reference/api/engine/#api-version-matrix)).
Users running older (end of life) versions of Docker Engine should update their
Docker Engine or use the [`DOCKER_API_VERSION`](https://docs.docker.com/reference/api/engine/#versioned-api-and-sdk)
environment variable to override the API version used by Traefik.
## v3.6.15
In `v3.6.15`, a new `errorRequestHeaders` option has been added to the Errors middleware.

24
go.mod
View File

@ -19,8 +19,7 @@ require (
github.com/containerd/errdefs v1.0.0
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd // No tag on the repo.
github.com/coreos/go-systemd/v22 v22.5.0
github.com/docker/cli v29.2.1+incompatible
github.com/docker/docker v28.5.2+incompatible
github.com/docker/cli v29.4.0+incompatible
github.com/docker/go-connections v0.6.0
github.com/fatih/structs v1.1.0
github.com/fsnotify/fsnotify v1.9.0
@ -50,6 +49,8 @@ require (
github.com/mitchellh/copystructure v1.2.0
github.com/mitchellh/hashstructure v1.0.0
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // No tag on the repo.
github.com/moby/moby/api v1.54.1
github.com/moby/moby/client v0.4.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pires/go-proxyproto v0.8.1
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo.
@ -58,15 +59,15 @@ require (
github.com/quic-go/quic-go v0.59.0
github.com/redis/go-redis/v9 v9.8.0
github.com/rs/zerolog v1.33.0
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.4
github.com/spiffe/go-spiffe/v2 v2.6.0
github.com/stealthrocket/wasi-go v0.8.0
github.com/stealthrocket/wazergo v0.19.1
github.com/stretchr/testify v1.11.1
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807 // No tag on the repo.
github.com/tailscale/tscert v0.0.0-20230806124524-28a91b69a046 // No tag on the repo.
github.com/testcontainers/testcontainers-go v0.40.0
github.com/testcontainers/testcontainers-go/modules/k3s v0.40.0
github.com/testcontainers/testcontainers-go v0.42.0
github.com/testcontainers/testcontainers-go/modules/k3s v0.42.0
github.com/tetratelabs/wazero v1.8.0
github.com/tidwall/gjson v1.17.0
github.com/traefik/grpc-web v0.16.0
@ -194,7 +195,7 @@ require (
github.com/distribution/reference v0.6.0 // indirect
github.com/dnsimple/dnsimple-go/v4 v4.0.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/exoscale/egoscale/v3 v3.1.34 // indirect
@ -294,8 +295,8 @@ require (
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/go-archive v0.2.0 // indirect
github.com/moby/patternmatcher v0.6.1 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
@ -303,7 +304,6 @@ require (
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // 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/v4 v4.0.2 // indirect
@ -349,7 +349,7 @@ require (
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 // indirect
github.com/selectel/domains-go v1.1.0 // indirect
github.com/selectel/go-selvpcclient/v4 v4.2.0 // indirect
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/shirou/gopsutil/v4 v4.26.3 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/softlayer/softlayer-go v1.2.1 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
@ -365,8 +365,8 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/transip/gotransip/v6 v6.26.2 // indirect
github.com/ucloud/ucloud-sdk-go v0.22.63 // indirect
github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419 // indirect

57
go.sum
View File

@ -920,8 +920,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -944,10 +944,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dnsimple/dnsimple-go/v4 v4.0.0 h1:nUCICZSyZDiiqimAAL+E8XL+0sKGks5VRki5S8XotRo=
github.com/dnsimple/dnsimple-go/v4 v4.0.0/go.mod h1:AXT2yfAFOntJx6iMeo1J/zKBw0ggXFYBt4e97dqqPnc=
github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/cli v29.4.0+incompatible h1:+IjXULMetlvWJiuSI0Nbor36lcJ5BTcVpUmB21KBoVM=
github.com/docker/cli v29.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@ -958,8 +956,8 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
@ -1627,14 +1625,16 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/moby/moby/api v1.54.1 h1:TqVzuJkOLsgLDDwNLmYqACUuTehOHRGKiPhvH8V3Nn4=
github.com/moby/moby/api v1.54.1/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjIw=
github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
@ -1652,8 +1652,6 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -1874,8 +1872,8 @@ github.com/selectel/domains-go v1.1.0 h1:futG50J43ALLKQAnZk9H9yOtLGnSUh7c5hSvuC5
github.com/selectel/domains-go v1.1.0/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
github.com/selectel/go-selvpcclient/v4 v4.2.0 h1:tVqSAdmNcdshv3AgfaIwGHs1oLk4jX8Tm+ccMg1rBmc=
github.com/selectel/go-selvpcclient/v4 v4.2.0/go.mod h1:eFhL1KUW159KOJVeGO7k/Uxl0TYd/sBkWXjuF5WxmYk=
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc=
github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk=
github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@ -1888,8 +1886,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@ -1975,10 +1973,10 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.24/go.mod h
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.38/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.83 h1:C8ro7XQVV17O+A7zUTe28VK02NuyazuaY0CB2CH5Scw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.83/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
github.com/testcontainers/testcontainers-go/modules/k3s v0.40.0 h1:3w6SjtIp/+FdpjWJCyPqaGWknG2iU6MacEWA7hl0IqQ=
github.com/testcontainers/testcontainers-go/modules/k3s v0.40.0/go.mod h1:1xJwmfO2g+XKox9LiJXKGCm1vWp7LozX+78UjXVRbF0=
github.com/testcontainers/testcontainers-go v0.42.0 h1:He3IhTzTZOygSXLJPMX7n44XtK+qhjat1nI9cneBbUY=
github.com/testcontainers/testcontainers-go v0.42.0/go.mod h1:vZjdY1YmUA1qEForxOIOazfsrdyORJAbhi0bp8plN30=
github.com/testcontainers/testcontainers-go/modules/k3s v0.42.0 h1:bTVmcnYaSHesN6HXXxV/k0+BMkyfo3VBy4w4yRqOIgE=
github.com/testcontainers/testcontainers-go/modules/k3s v0.42.0/go.mod h1:2O8+V4WzMb/bjg/Sez+aYci9LpGUbT5cSz7ildfTIb8=
github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g=
github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
@ -1991,10 +1989,10 @@ github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltascY=
github.com/traefik/grpc-web v0.16.0/go.mod h1:2ttniSv7pTgBWIU2HZLokxRfFX3SA60c/DTmQQgVml4=
@ -2555,7 +2553,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -3113,6 +3110,8 @@ mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8=
mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

View File

@ -11,6 +11,7 @@ import (
"io/fs"
stdlog "log"
"net/http"
"net/netip"
"os"
"os/exec"
"path/filepath"
@ -22,10 +23,11 @@ import (
"text/template"
"time"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
dockernetwork "github.com/docker/docker/api/types/network"
"github.com/fatih/structs"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/mount"
dockernetwork "github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
@ -97,7 +99,7 @@ func (s *BaseSuite) SetupSuite() {
Driver: "default",
Config: []dockernetwork.IPAMConfig{
{
Subnet: "172.31.42.0/24",
Subnet: netip.MustParsePrefix("172.31.42.0/24"),
},
},
}))
@ -150,12 +152,12 @@ func isDockerDesktop(t *testing.T) bool {
t.Fatalf("failed to create docker client: %s", err)
}
info, err := cli.Info(t.Context())
res, err := cli.Info(t.Context(), client.InfoOptions{})
if err != nil {
t.Fatalf("failed to get docker info: %s", err)
}
return info.OperatingSystem == "Docker Desktop"
return res.Info.OperatingSystem == "Docker Desktop"
}
func (s *BaseSuite) TearDownSuite() {
@ -195,24 +197,28 @@ func (s *BaseSuite) createComposeProject(name string) {
for id, containerConfig := range composeConfigData.Services {
var mounts []mount.Mount
for _, volume := range containerConfig.Volumes {
split := strings.Split(volume, ":")
if len(split) != 2 {
src, dst, ok := strings.Cut(volume, ":")
if !ok {
continue
}
if strings.HasPrefix(split[0], "./") {
path, err := os.Getwd()
if strings.HasPrefix(src, "./") {
wd, err := os.Getwd()
if err != nil {
log.Err(err).Msg("can't determine current directory")
continue
}
split[0] = strings.Replace(split[0], "./", path+"/", 1)
src = wd + "/" + strings.TrimPrefix(src, "./")
}
abs, err := filepath.Abs(split[0])
abs, err := filepath.Abs(src)
require.NoError(s.T(), err)
mounts = append(mounts, mount.Mount{Source: abs, Target: split[1], Type: mount.TypeBind})
mounts = append(mounts, mount.Mount{
Source: abs,
Target: dst,
Type: mount.TypeBind,
})
}
if containerConfig.Deploy.Replicas > 0 {

View File

@ -1,19 +1,18 @@
package docker
import (
containertypes "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/go-connections/nat"
"net/netip"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
)
func containerJSON(ops ...func(*containertypes.InspectResponse)) containertypes.InspectResponse {
c := &containertypes.InspectResponse{
ContainerJSONBase: &containertypes.ContainerJSONBase{
Name: "fake",
HostConfig: &containertypes.HostConfig{},
State: &containertypes.State{},
},
Name: "fake",
HostConfig: &containertypes.HostConfig{},
State: &containertypes.State{},
Config: &containertypes.Config{},
NetworkSettings: &containertypes.NetworkSettings{},
}
@ -27,17 +26,17 @@ func containerJSON(ops ...func(*containertypes.InspectResponse)) containertypes.
func name(name string) func(*containertypes.InspectResponse) {
return func(c *containertypes.InspectResponse) {
c.ContainerJSONBase.Name = name
c.Name = name
}
}
func networkMode(mode string) func(*containertypes.InspectResponse) {
return func(c *containertypes.InspectResponse) {
c.ContainerJSONBase.HostConfig.NetworkMode = containertypes.NetworkMode(mode)
c.HostConfig.NetworkMode = containertypes.NetworkMode(mode)
}
}
func ports(portMap nat.PortMap) func(*containertypes.InspectResponse) {
func ports(portMap networktypes.PortMap) func(*containertypes.InspectResponse) {
return func(c *containertypes.InspectResponse) {
c.NetworkSettings.Ports = portMap
}
@ -57,13 +56,13 @@ func withNetwork(name string, ops ...func(*networktypes.EndpointSettings)) func(
func ipv4(ip string) func(*networktypes.EndpointSettings) {
return func(s *networktypes.EndpointSettings) {
s.IPAddress = ip
s.IPAddress = netip.MustParseAddr(ip).Unmap()
}
}
func ipv6(ip string) func(*networktypes.EndpointSettings) {
return func(s *networktypes.EndpointSettings) {
s.GlobalIPv6Address = ip
s.GlobalIPv6Address = netip.MustParseAddr(ip)
}
}
@ -92,20 +91,20 @@ func taskNodeID(id string) func(*swarmtypes.Task) {
}
func taskNetworkAttachment(id, name, driver string, addresses []string) func(*swarmtypes.Task) {
prefixes := make([]netip.Prefix, len(addresses))
for i, s := range addresses {
prefixes[i] = mustParseAddrOrPrefix(s)
}
return func(task *swarmtypes.Task) {
task.NetworksAttachments = append(task.NetworksAttachments, swarmtypes.NetworkAttachment{
Network: swarmtypes.Network{
ID: id,
Spec: swarmtypes.NetworkSpec{
Annotations: swarmtypes.Annotations{
Name: name,
},
DriverConfiguration: &swarmtypes.Driver{
Name: driver,
},
Annotations: swarmtypes.Annotations{Name: name},
DriverConfiguration: &swarmtypes.Driver{Name: driver},
},
},
Addresses: addresses,
Addresses: prefixes,
})
}
}
@ -184,7 +183,7 @@ func virtualIP(networkID, addr string) func(*swarmtypes.Endpoint) {
}
endpoint.VirtualIPs = append(endpoint.VirtualIPs, swarmtypes.EndpointVirtualIP{
NetworkID: networkID,
Addr: addr,
Addr: mustParseAddrOrPrefix(addr),
})
}
}
@ -208,3 +207,21 @@ func modeDNSRR(spec *swarmtypes.EndpointSpec) {
func modeVIP(spec *swarmtypes.EndpointSpec) {
spec.Mode = swarmtypes.ResolutionModeVIP
}
// mustParseAddrOrPrefix parses addrOrPrefix into a [netip.Prefix].
//
// We should expect only IP-addresses, but for backwards-compatibility,
// the Addresses field on [swarmtypes.NetworkAttachment] accepts a prefix.
func mustParseAddrOrPrefix(addrOrPrefix string) netip.Prefix {
if addrOrPrefix == "" {
return netip.Prefix{}
}
if p, err := netip.ParsePrefix(addrOrPrefix); err == nil {
return p
}
a := netip.MustParseAddr(addrOrPrefix)
if a.Is4() {
return netip.PrefixFrom(a, 32)
}
return netip.PrefixFrom(a, 128)
}

View File

@ -7,9 +7,9 @@ import (
"net"
"strings"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/label"
@ -335,10 +335,10 @@ func (p *DynConfBuilder) getIPPort(ctx context.Context, container dockerData, se
switch {
case err != nil:
logger.Info().Msgf("Unable to find a binding for container %q, falling back on its internal IP/Port.", container.Name)
case portBinding.HostIP == "0.0.0.0" || len(portBinding.HostIP) == 0:
case portBinding.HostIP.IsUnspecified() || !portBinding.HostIP.IsValid():
logger.Info().Msgf("Cannot determine the IP address (got %q) for %q's binding, falling back on its internal IP/Port.", portBinding.HostIP, container.Name)
default:
ip = portBinding.HostIP
ip = portBinding.HostIP.String()
port = portBinding.HostPort
usedBound = true
}
@ -387,7 +387,7 @@ func (p *DynConfBuilder) getIPAddress(ctx context.Context, container dockerData)
if container.NetworkSettings.NetworkMode.IsContainer() {
connectedContainer := container.NetworkSettings.NetworkMode.ConnectedContainer()
containerInspected, err := p.apiClient.ContainerInspect(context.Background(), connectedContainer)
res, err := p.apiClient.ContainerInspect(context.Background(), connectedContainer, client.ContainerInspectOptions{})
if err != nil {
logger.Warn().Err(err).Msgf("Unable to get IP address for container %s: failed to inspect container ID %s", container.Name, connectedContainer)
return ""
@ -395,10 +395,10 @@ func (p *DynConfBuilder) getIPAddress(ctx context.Context, container dockerData)
// Check connected container for traefik.docker.network,
// falling back to the network specified on the current container.
containerParsed := parseContainer(containerInspected)
containerParsed := parseContainer(res.Container)
extraConf, err := p.extractLabels(containerParsed)
if err != nil {
logger.Warn().Err(err).Msgf("Unable to get IP address for container %s: failed to get extra configuration for container %s", container.Name, containerInspected.Name)
logger.Warn().Err(err).Msgf("Unable to get IP address for container %s: failed to get extra configuration for container %s", container.Name, res.Container.Name)
return ""
}
@ -424,11 +424,11 @@ func (p *DynConfBuilder) getIPAddress(ctx context.Context, container dockerData)
return ""
}
func (p *DynConfBuilder) getPortBinding(container dockerData, serverPort string) (*nat.PortBinding, error) {
func (p *DynConfBuilder) getPortBinding(container dockerData, serverPort string) (*networktypes.PortBinding, error) {
port := getPort(container, serverPort)
for netPort, portBindings := range container.NetworkSettings.Ports {
if strings.EqualFold(string(netPort), port+"/TCP") || strings.EqualFold(string(netPort), port+"/UDP") {
if netPort.Port() == port && (netPort.Proto() == networktypes.TCP || netPort.Proto() == networktypes.UDP) {
for _, p := range portBindings {
return &p, nil
}

View File

@ -1,14 +1,14 @@
package docker
import (
"net/netip"
"strconv"
"testing"
"time"
containertypes "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/go-connections/nat"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
@ -33,8 +33,8 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -97,8 +97,8 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -163,8 +163,8 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
"traefik.domain": "foo.bar",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -227,8 +227,8 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -285,8 +285,8 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -343,8 +343,8 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -447,8 +447,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.test": "",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -491,8 +491,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tcp.services.test": "",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -535,8 +535,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.udp.services.test": "",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/udp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/udp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -577,8 +577,8 @@ func TestDynConfBuilder_build(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -640,8 +640,8 @@ func TestDynConfBuilder_build(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -656,8 +656,8 @@ func TestDynConfBuilder_build(t *testing.T) {
Name: "Test2",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -739,8 +739,8 @@ func TestDynConfBuilder_build(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -756,8 +756,8 @@ func TestDynConfBuilder_build(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -824,8 +824,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -891,8 +891,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.service": "Service1",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -955,8 +955,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1020,8 +1020,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1086,8 +1086,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service2.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1160,8 +1160,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.service": "Service1",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1225,8 +1225,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1244,8 +1244,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "false",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1295,8 +1295,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "false",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1314,8 +1314,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1333,8 +1333,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1384,8 +1384,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1403,8 +1403,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1471,8 +1471,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1543,8 +1543,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1562,8 +1562,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1637,8 +1637,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1656,8 +1656,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "41",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1725,8 +1725,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1744,8 +1744,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "41",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1763,8 +1763,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "40",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1835,8 +1835,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1854,8 +1854,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`bar.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1917,8 +1917,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1936,8 +1936,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`bar.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -1955,8 +1955,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foobar.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2021,8 +2021,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2040,8 +2040,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2107,8 +2107,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2125,8 +2125,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2198,8 +2198,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.wrong.label": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2264,8 +2264,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.LoadBalancer.server.port": "8080",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2330,8 +2330,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service2.LoadBalancer.server.port": "8080",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2403,8 +2403,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("4567/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2469,8 +2469,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.LoadBalancer.server.preservepath": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("4567/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2536,8 +2536,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.LoadBalancer.server.port": "1234",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("4567/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2581,8 +2581,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.LoadBalancer.server.scheme": "https",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("4567/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2623,7 +2623,7 @@ func TestDynConfBuilder_build(t *testing.T) {
Name: "Test",
Labels: map[string]string{},
NetworkSettings: networkSettings{
Ports: nat.PortMap{},
Ports: networktypes.PortMap{},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
@ -2665,7 +2665,7 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{},
Ports: networktypes.PortMap{},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
@ -2707,8 +2707,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.enable": "false",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -2985,8 +2985,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tags": "foo",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3030,8 +3030,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tags": "foo",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3097,8 +3097,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.routers.Test.middlewares": "Middleware1",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3174,8 +3174,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tcp.routers.Test.middlewares": "Middleware1",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3241,8 +3241,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tcp.routers.foo.tls": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3301,8 +3301,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.udp.routers.foo.entrypoints": "mydns",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3360,8 +3360,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tcp.routers.foo.tls": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3416,8 +3416,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3479,8 +3479,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.udp.services.foo.loadbalancer.server.port": "8080",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3540,8 +3540,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3561,8 +3561,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3647,8 +3647,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.udp.services.foo.loadbalancer.server.port": "8080",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3702,8 +3702,8 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("80/tcp"): []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -3756,13 +3756,13 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.http.services.Test.loadbalancer.server.port": "80",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("79/tcp"): []nat.PortBinding{{
HostIP: "192.168.0.1",
Ports: networktypes.PortMap{
networktypes.MustParsePort("79/tcp"): []networktypes.PortBinding{{
HostIP: netip.MustParseAddr("192.168.0.1"),
HostPort: "8080",
}},
nat.Port("80/tcp"): []nat.PortBinding{{
HostIP: "192.168.0.1",
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{{
HostIP: netip.MustParseAddr("192.168.0.1"),
HostPort: "8081",
}},
},
@ -3831,13 +3831,13 @@ func TestDynConfBuilder_build(t *testing.T) {
"traefik.tls.stores.default.defaultgeneratedcert.domain.sans": "foobar, fiibar",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("79/tcp"): []nat.PortBinding{{
HostIP: "192.168.0.1",
Ports: networktypes.PortMap{
networktypes.MustParsePort("79/tcp"): []networktypes.PortBinding{{
HostIP: netip.MustParseAddr("192.168.0.1"),
HostPort: "8080",
}},
nat.Port("80/tcp"): []nat.PortBinding{{
HostIP: "192.168.0.1",
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{{
HostIP: netip.MustParseAddr("192.168.0.1"),
HostPort: "8081",
}},
},
@ -3956,8 +3956,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/tcp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4020,8 +4020,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/tcp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4068,8 +4068,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/tcp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4137,8 +4137,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/tcp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4201,8 +4201,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/tcp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4268,8 +4268,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/tcp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4328,8 +4328,8 @@ func TestDynConfBuilder_build_allowNonRunning(t *testing.T) {
},
NetworkSettings: networkSettings{
NetworkMode: "bridge",
Ports: nat.PortMap{
"80/udp": []nat.PortBinding{},
Ports: networktypes.PortMap{
networktypes.MustParsePort("80/udp"): []networktypes.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
@ -4410,8 +4410,8 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
{
desc: "label traefik.port not set, no binding, falling back on the container's IP/Port",
container: containerJSON(
ports(nat.PortMap{
"8080/tcp": {},
ports(networktypes.PortMap{
networktypes.MustParsePort("8080/tcp"): {},
}),
withNetwork("testnet", ipv4("10.11.12.13"))),
expected: expected{
@ -4423,8 +4423,8 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
desc: "label traefik.port not set, single binding with port only, falling back on the container's IP/Port",
container: containerJSON(
withNetwork("testnet", ipv4("10.11.12.13")),
ports(nat.PortMap{
"80/tcp": []nat.PortBinding{
ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{
{
HostPort: "8082",
},
@ -4439,10 +4439,10 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
{
desc: "label traefik.port not set, binding with ip:port should create a route to the bound ip:port",
container: containerJSON(
ports(nat.PortMap{
"80/tcp": []nat.PortBinding{
ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{
{
HostIP: "1.2.3.4",
HostIP: netip.MustParseAddr("1.2.3.4"),
HostPort: "8081",
},
},
@ -4465,10 +4465,10 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
{
desc: "label traefik.port set, single binding with ip:port for the label, creates the route",
container: containerJSON(
ports(nat.PortMap{
"443/tcp": []nat.PortBinding{
ports(networktypes.PortMap{
networktypes.MustParsePort("443/tcp"): []networktypes.PortBinding{
{
HostIP: "5.6.7.8",
HostIP: netip.MustParseAddr("5.6.7.8"),
HostPort: "8082",
},
},
@ -4483,10 +4483,10 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
{
desc: "label traefik.port set, no binding on the corresponding port, falling back on the container's IP/label.port",
container: containerJSON(
ports(nat.PortMap{
"443/tcp": []nat.PortBinding{
ports(networktypes.PortMap{
networktypes.MustParsePort("443/tcp"): []networktypes.PortBinding{
{
HostIP: "5.6.7.8",
HostIP: netip.MustParseAddr("5.6.7.8"),
HostPort: "8082",
},
},
@ -4501,16 +4501,16 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
{
desc: "label traefik.port set, multiple bindings on different ports, uses the label to select the correct (first) binding",
container: containerJSON(
ports(nat.PortMap{
"80/tcp": []nat.PortBinding{
ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{
{
HostIP: "1.2.3.4",
HostIP: netip.MustParseAddr("1.2.3.4"),
HostPort: "8081",
},
},
"443/tcp": []nat.PortBinding{
networktypes.MustParsePort("443/tcp"): []networktypes.PortBinding{
{
HostIP: "5.6.7.8",
HostIP: netip.MustParseAddr("5.6.7.8"),
HostPort: "8082",
},
},
@ -4525,16 +4525,16 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
{
desc: "label traefik.port set, multiple bindings on different ports, uses the label to select the correct (second) binding",
container: containerJSON(
ports(nat.PortMap{
"80/tcp": []nat.PortBinding{
ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): []networktypes.PortBinding{
{
HostIP: "1.2.3.4",
HostIP: netip.MustParseAddr("1.2.3.4"),
HostPort: "8081",
},
},
"443/tcp": []nat.PortBinding{
networktypes.MustParsePort("443/tcp"): []networktypes.PortBinding{
{
HostIP: "5.6.7.8",
HostIP: netip.MustParseAddr("5.6.7.8"),
HostPort: "8082",
},
},
@ -4706,7 +4706,7 @@ func TestDynConfBuilder_getIPAddress_swarm(t *testing.T) {
expected: "10.11.12.13",
networks: map[string]*networktypes.Summary{
"1": {
Name: "foo",
Network: networktypes.Network{Name: "foo"},
},
},
},
@ -4724,10 +4724,10 @@ func TestDynConfBuilder_getIPAddress_swarm(t *testing.T) {
expected: "10.11.12.99",
networks: map[string]*networktypes.Summary{
"1": {
Name: "foonet",
Network: networktypes.Network{Name: "foonet"},
},
"2": {
Name: "barnet",
Network: networktypes.Network{Name: "barnet"},
},
},
},

View File

@ -1,8 +1,8 @@
package docker
import (
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
)
// dockerData holds the need data to the provider.
@ -10,10 +10,10 @@ type dockerData struct {
ID string
ServiceName string
Name string
Status string
Status containertypes.ContainerState
Labels map[string]string // List of labels set to container or service
NetworkSettings networkSettings
Health string
Health containertypes.HealthStatus
NodeIP string // Only filled in Swarm mode.
ExtraConf configuration
}
@ -21,7 +21,7 @@ type dockerData struct {
// NetworkSettings holds the networks data to the provider.
type networkSettings struct {
NetworkMode containertypes.NetworkMode
Ports nat.PortMap
Ports networktypes.PortMap
Networks map[string]*networkData
}

View File

@ -9,10 +9,8 @@ import (
"time"
"github.com/cenkalti/backoff/v4"
"github.com/docker/docker/api/types/container"
eventtypes "github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
eventtypes "github.com/moby/moby/api/types/events"
"github.com/moby/moby/client"
"github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/job"
@ -72,7 +70,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
builder := NewDynConfBuilder(p.Shared, dockerClient, false)
serverVersion, err := dockerClient.ServerVersion(ctx)
serverVersion, err := dockerClient.ServerVersion(ctx, client.ServerVersionOptions{})
if err != nil {
logger.Error().Err(err).Msg("Failed to retrieve information of the docker client and server host")
return err
@ -93,12 +91,6 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
}
if p.Watch {
f := filters.NewArgs()
f.Add("type", "container")
options := eventtypes.ListOptions{
Filters: f,
}
startStopHandle := func(m eventtypes.Message) {
logger.Debug().Msgf("Provider event received %+v", m)
containers, err := p.listContainers(ctx, dockerClient)
@ -121,16 +113,18 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
}
}
eventsc, errc := dockerClient.Events(ctx, options)
res := dockerClient.Events(ctx, client.EventsListOptions{
Filters: make(client.Filters).Add("type", string(eventtypes.ContainerEventType)),
})
for {
select {
case event := <-eventsc:
case event := <-res.Messages:
if event.Action == "start" ||
event.Action == "die" ||
strings.HasPrefix(string(event.Action), "health_status") {
startStopHandle(event)
}
case err := <-errc:
case err := <-res.Err:
if errors.Is(err, io.EOF) {
logger.Debug().Msg("Provider event stream closed")
}
@ -161,7 +155,7 @@ func (p *Provider) createClient(ctx context.Context) (*client.Client, error) {
}
func (p *Provider) listContainers(ctx context.Context, dockerClient client.ContainerAPIClient) ([]dockerData, error) {
containerList, err := dockerClient.ContainerList(ctx, container.ListOptions{
containerList, err := dockerClient.ContainerList(ctx, client.ContainerListOptions{
All: true,
})
if err != nil {
@ -170,7 +164,7 @@ func (p *Provider) listContainers(ctx context.Context, dockerClient client.Conta
var inspectedContainers []dockerData
// get inspect containers
for _, c := range containerList {
for _, c := range containerList.Items {
dData := inspectContainers(ctx, dockerClient, c.ID)
if len(dData.Name) == 0 {
continue

View File

@ -3,16 +3,14 @@ package docker
import (
"context"
"fmt"
"net"
"strconv"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/docker/docker/api/types/filters"
networktypes "github.com/docker/docker/api/types/network"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client"
networktypes "github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/client/pkg/versions"
"github.com/rs/zerolog/log"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
@ -76,7 +74,7 @@ func (p *SwarmProvider) Provide(configurationChan chan<- dynamic.Message, pool *
builder := NewDynConfBuilder(p.Shared, dockerClient, true)
serverVersion, err := dockerClient.ServerVersion(ctx)
serverVersion, err := dockerClient.ServerVersion(ctx, client.ServerVersionOptions{})
if err != nil {
logger.Error().Err(err).Msg("Failed to retrieve information of the docker client and server host")
return err
@ -157,17 +155,17 @@ func (p *SwarmProvider) createClient(ctx context.Context) (*client.Client, error
func (p *SwarmProvider) listServices(ctx context.Context, dockerClient client.APIClient) ([]dockerData, error) {
logger := log.Ctx(ctx)
serviceList, err := dockerClient.ServiceList(ctx, swarmtypes.ServiceListOptions{})
serviceList, err := dockerClient.ServiceList(ctx, client.ServiceListOptions{})
if err != nil {
return nil, err
}
serverVersion, err := dockerClient.ServerVersion(ctx)
serverVersion, err := dockerClient.ServerVersion(ctx, client.ServerVersionOptions{})
if err != nil {
return nil, err
}
networkListArgs := filters.NewArgs()
networkListArgs := client.Filters{}
// https://docs.docker.com/engine/api/v1.29/#tag/Network (Docker 17.06)
if versions.GreaterThanOrEqualTo(serverVersion.APIVersion, "1.29") {
networkListArgs.Add("scope", "swarm")
@ -175,21 +173,23 @@ func (p *SwarmProvider) listServices(ctx context.Context, dockerClient client.AP
networkListArgs.Add("driver", "overlay")
}
networkList, err := dockerClient.NetworkList(ctx, networktypes.ListOptions{Filters: networkListArgs})
networkList, err := dockerClient.NetworkList(ctx, client.NetworkListOptions{
Filters: networkListArgs,
})
if err != nil {
logger.Debug().Err(err).Msg("Failed to network inspect on client for docker")
return nil, err
}
networkMap := make(map[string]*networktypes.Summary)
for _, network := range networkList {
for _, network := range networkList.Items {
networkMap[network.ID] = &network
}
var dockerDataList []dockerData
var dockerDataListTasks []dockerData
for _, service := range serviceList {
for _, service := range serviceList.Items {
dData, err := p.parseService(ctx, service, networkMap)
if err != nil {
logger.Error().Err(err).Msgf("Skip container %s", getServiceName(dData))
@ -246,15 +246,14 @@ func (p *SwarmProvider) parseService(ctx context.Context, service swarmtypes.Ser
logger.Debug().Msgf("Network not found, id: %s", virtualIP.NetworkID)
continue
}
if len(virtualIP.Addr) == 0 {
if !virtualIP.Addr.Addr().IsValid() {
logger.Debug().Msgf("No virtual IPs found in network %s", virtualIP.NetworkID)
continue
}
ip, _, _ := net.ParseCIDR(virtualIP.Addr)
network := &networkData{
Name: networkService.Name,
ID: virtualIP.NetworkID,
Addr: ip.String(),
Addr: virtualIP.Addr.Addr().String(),
}
dData.NetworkSettings.Networks[network.Name] = network
}
@ -265,17 +264,15 @@ func (p *SwarmProvider) parseService(ctx context.Context, service swarmtypes.Ser
func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID string,
serviceDockerData dockerData, networkMap map[string]*networktypes.Summary, isGlobalSvc bool,
) ([]dockerData, error) {
serviceIDFilter := filters.NewArgs()
serviceIDFilter.Add("service", serviceID)
serviceIDFilter.Add("desired-state", "running")
taskList, err := dockerClient.TaskList(ctx, swarmtypes.TaskListOptions{Filters: serviceIDFilter})
taskList, err := dockerClient.TaskList(ctx, client.TaskListOptions{
Filters: make(client.Filters).Add("service", serviceID).Add("desired-state", "running"),
})
if err != nil {
return nil, err
}
var dockerDataList []dockerData
for _, task := range taskList {
for _, task := range taskList.Items {
if task.Status.State != swarmtypes.TaskStateRunning {
continue
}
@ -308,11 +305,11 @@ func parseTasks(ctx context.Context, dockerClient client.APIClient, task swarmty
}
if task.NodeID != "" {
node, _, err := dockerClient.NodeInspectWithRaw(ctx, task.NodeID)
res, err := dockerClient.NodeInspect(ctx, task.NodeID, client.NodeInspectOptions{})
if err != nil {
return dockerData{}, fmt.Errorf("inspecting node %s: %w", task.NodeID, err)
}
dData.NodeIP = node.Status.Addr
dData.NodeIP = res.Node.Status.Addr
}
if task.NetworksAttachments != nil {
@ -322,11 +319,14 @@ func parseTasks(ctx context.Context, dockerClient client.APIClient, task swarmty
if len(virtualIP.Addresses) > 0 {
// Not sure about this next loop - when would a task have multiple IP's for the same network?
for _, addr := range virtualIP.Addresses {
ip, _, _ := net.ParseCIDR(addr)
var ip string
if addr.IsValid() {
ip = addr.Addr().String()
}
network := &networkData{
ID: virtualIP.Network.ID,
Name: networkService.Name,
Addr: ip.String(),
Addr: ip,
}
dData.NetworkSettings.Networks[network.Name] = network
}

View File

@ -3,31 +3,30 @@ package docker
import (
"context"
dockertypes "github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
swarmtypes "github.com/docker/docker/api/types/swarm"
dockerclient "github.com/docker/docker/client"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
)
type fakeTasksClient struct {
dockerclient.APIClient
client.APIClient
tasks []swarmtypes.Task
container containertypes.InspectResponse
err error
}
func (c *fakeTasksClient) TaskList(ctx context.Context, options swarmtypes.TaskListOptions) ([]swarmtypes.Task, error) {
return c.tasks, c.err
func (c *fakeTasksClient) TaskList(ctx context.Context, options client.TaskListOptions) (client.TaskListResult, error) {
return client.TaskListResult{Items: c.tasks}, c.err
}
func (c *fakeTasksClient) ContainerInspect(ctx context.Context, container string) (containertypes.InspectResponse, error) {
return c.container, c.err
func (c *fakeTasksClient) ContainerInspect(ctx context.Context, container string, options client.ContainerInspectOptions) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{Container: c.container}, c.err
}
type fakeServicesClient struct {
dockerclient.APIClient
client.APIClient
dockerVersion string
networks []networktypes.Summary
@ -37,27 +36,29 @@ type fakeServicesClient struct {
err error
}
func (c *fakeServicesClient) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarmtypes.Node, []byte, error) {
func (c *fakeServicesClient) NodeInspect(ctx context.Context, nodeID string, options client.NodeInspectOptions) (client.NodeInspectResult, error) {
for _, node := range c.nodes {
if node.ID == nodeID {
return node, nil, nil
return client.NodeInspectResult{
Node: node,
}, nil
}
}
return swarmtypes.Node{}, nil, c.err
return client.NodeInspectResult{}, c.err
}
func (c *fakeServicesClient) ServiceList(ctx context.Context, options swarmtypes.ServiceListOptions) ([]swarmtypes.Service, error) {
return c.services, c.err
func (c *fakeServicesClient) ServiceList(ctx context.Context, options client.ServiceListOptions) (client.ServiceListResult, error) {
return client.ServiceListResult{Items: c.services}, c.err
}
func (c *fakeServicesClient) ServerVersion(ctx context.Context) (dockertypes.Version, error) {
return dockertypes.Version{APIVersion: c.dockerVersion}, c.err
func (c *fakeServicesClient) ServerVersion(ctx context.Context, options client.ServerVersionOptions) (client.ServerVersionResult, error) {
return client.ServerVersionResult{APIVersion: c.dockerVersion}, c.err
}
func (c *fakeServicesClient) NetworkList(ctx context.Context, options networktypes.ListOptions) ([]networktypes.Summary, error) {
return c.networks, c.err
func (c *fakeServicesClient) NetworkList(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) {
return client.NetworkListResult{Items: c.networks}, c.err
}
func (c *fakeServicesClient) TaskList(ctx context.Context, options swarmtypes.TaskListOptions) ([]swarmtypes.Task, error) {
return c.tasks, c.err
func (c *fakeServicesClient) TaskList(ctx context.Context, options client.TaskListOptions) (client.TaskListResult, error) {
return client.TaskListResult{Items: c.tasks}, c.err
}

View File

@ -5,8 +5,8 @@ import (
"testing"
"time"
networktypes "github.com/docker/docker/api/types/network"
swarmtypes "github.com/docker/docker/api/types/swarm"
networktypes "github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -46,15 +46,21 @@ func TestListTasks(t *testing.T) {
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.5"}),
taskStatus(taskState(swarmtypes.TaskStateFailed)),
),
swarmTask("id6",
taskSlot(6),
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.6/24"}),
taskStatus(taskState(swarmtypes.TaskStateRunning)),
),
},
isGlobalSVC: false,
expectedTasks: []string{
"container.1",
"container.4",
"container.6",
},
networks: map[string]*networktypes.Summary{
"1": {
Name: "foo",
Network: networktypes.Network{Name: "foo"},
},
},
},
@ -146,21 +152,23 @@ func TestSwarmProvider_listServices(t *testing.T) {
dockerVersion: "1.30",
networks: []networktypes.Summary{
{
Name: "network_name",
ID: "yk6l57rfwizjzxxzftn4amaot",
Created: time.Now(),
Scope: "swarm",
Driver: "overlay",
EnableIPv6: false,
Internal: true,
Ingress: false,
ConfigOnly: false,
Options: map[string]string{
"com.docker.networktypes.driver.overlay.vxlanid_list": "4098",
"com.docker.networktypes.enable_ipv6": "false",
},
Labels: map[string]string{
"com.docker.stack.namespace": "test",
Network: networktypes.Network{
Name: "network_name",
ID: "yk6l57rfwizjzxxzftn4amaot",
Created: time.Now(),
Scope: "swarm",
Driver: "overlay",
EnableIPv6: false,
Internal: true,
Ingress: false,
ConfigOnly: false,
Options: map[string]string{
"com.docker.networktypes.driver.overlay.vxlanid_list": "4098",
"com.docker.networktypes.enable_ipv6": "false",
},
Labels: map[string]string{
"com.docker.stack.namespace": "test",
},
},
},
},
@ -201,21 +209,23 @@ func TestSwarmProvider_listServices(t *testing.T) {
dockerVersion: "1.30",
networks: []networktypes.Summary{
{
Name: "network_name",
ID: "yk6l57rfwizjzxxzftn4amaot",
Created: time.Now(),
Scope: "swarm",
Driver: "overlay",
EnableIPv6: false,
Internal: true,
Ingress: false,
ConfigOnly: false,
Options: map[string]string{
"com.docker.networktypes.driver.overlay.vxlanid_list": "4098",
"com.docker.networktypes.enable_ipv6": "false",
},
Labels: map[string]string{
"com.docker.stack.namespace": "test",
Network: networktypes.Network{
Name: "network_name",
ID: "yk6l57rfwizjzxxzftn4amaot",
Created: time.Now(),
Scope: "swarm",
Driver: "overlay",
EnableIPv6: false,
Internal: true,
Ingress: false,
ConfigOnly: false,
Options: map[string]string{
"com.docker.networktypes.driver.overlay.vxlanid_list": "4098",
"com.docker.networktypes.enable_ipv6": "false",
},
Labels: map[string]string{
"com.docker.stack.namespace": "test",
},
},
},
},
@ -281,7 +291,7 @@ func TestSwarmProvider_parseService_task(t *testing.T) {
},
networks: map[string]*networktypes.Summary{
"1": {
Name: "foo",
Network: networktypes.Network{Name: "foo"},
},
},
},
@ -306,7 +316,7 @@ func TestSwarmProvider_parseService_task(t *testing.T) {
},
networks: map[string]*networktypes.Summary{
"1": {
Name: "foo",
Network: networktypes.Network{Name: "foo"},
},
},
},
@ -344,7 +354,7 @@ func TestSwarmProvider_parseService_task(t *testing.T) {
},
networks: map[string]*networktypes.Summary{
"1": {
Name: "vlan",
Network: networktypes.Network{Name: "vlan"},
},
},
},
@ -372,7 +382,7 @@ func TestSwarmProvider_parseService_task(t *testing.T) {
},
networks: map[string]*networktypes.Summary{
"1": {
Name: "foo",
Network: networktypes.Network{Name: "vlan"},
},
},
},

View File

@ -1,19 +1,21 @@
package docker
import (
"cmp"
"context"
"encoding/base64"
"fmt"
"net/http"
"slices"
"text/template"
"time"
"github.com/containerd/errdefs"
"github.com/docker/cli/cli/connhelper"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/docker/go-connections/sockets"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/rs/zerolog/log"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/provider"
@ -38,7 +40,7 @@ type Shared struct {
}
func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClient, containerID string) dockerData {
containerInspected, err := dockerClient.ContainerInspect(ctx, containerID)
res, err := dockerClient.ContainerInspect(ctx, containerID, client.ContainerInspectOptions{})
if err != nil {
if errdefs.IsNotFound(err) {
log.Ctx(ctx).Debug().Err(err).Msgf("Failed to inspect container %s", containerID)
@ -50,8 +52,8 @@ func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClie
// Always parse all containers (running and stopped)
// The allowNonRunning filtering will be applied later in service configuration
if containerInspected.ContainerJSONBase != nil && containerInspected.ContainerJSONBase.State != nil {
return parseContainer(containerInspected)
if res.Container.State != nil {
return parseContainer(res.Container)
}
return dockerData{}
@ -59,22 +61,19 @@ func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClie
func parseContainer(container containertypes.InspectResponse) dockerData {
dData := dockerData{
ID: container.ID,
ServiceName: container.Name, // Default ServiceName to be the container's Name.
Name: container.Name,
Status: container.State.Status,
NetworkSettings: networkSettings{},
}
if container.ContainerJSONBase != nil {
dData.ID = container.ContainerJSONBase.ID
dData.Name = container.ContainerJSONBase.Name
dData.ServiceName = dData.Name // Default ServiceName to be the container's Name.
dData.Status = container.ContainerJSONBase.State.Status
if container.HostConfig != nil {
dData.NetworkSettings.NetworkMode = container.HostConfig.NetworkMode
}
if container.ContainerJSONBase.HostConfig != nil {
dData.NetworkSettings.NetworkMode = container.ContainerJSONBase.HostConfig.NetworkMode
}
if container.State != nil && container.State.Health != nil {
dData.Health = container.State.Health.Status
}
if container.State != nil && container.State.Health != nil {
dData.Health = container.State.Health.Status
}
if container.Config != nil && container.Config.Labels != nil {
@ -88,11 +87,12 @@ func parseContainer(container containertypes.InspectResponse) dockerData {
if container.NetworkSettings.Networks != nil {
dData.NetworkSettings.Networks = make(map[string]*networkData)
for name, containerNetwork := range container.NetworkSettings.Networks {
addr := containerNetwork.IPAddress
if addr == "" {
addr = containerNetwork.GlobalIPv6Address
var addr string
if containerNetwork.IPAddress.IsValid() {
addr = containerNetwork.IPAddress.String()
} else if containerNetwork.GlobalIPv6Address.IsValid() {
addr = containerNetwork.GlobalIPv6Address.String()
}
dData.NetworkSettings.Networks[name] = &networkData{
ID: containerNetwork.NetworkID,
Name: name,
@ -127,10 +127,9 @@ func createClient(ctx context.Context, cfg ClientConfig) (*client.Client, error)
opts = append(opts,
client.FromEnv,
client.WithAPIVersionNegotiation(),
client.WithHTTPHeaders(httpHeaders))
return client.NewClientWithOpts(opts...)
return client.New(opts...)
}
func getClientOpts(ctx context.Context, cfg ClientConfig) ([]client.Opt, error) {
@ -191,22 +190,20 @@ func getPort(container dockerData, serverPort string) string {
if len(serverPort) > 0 {
return serverPort
}
if len(container.NetworkSettings.Ports) == 0 {
return ""
}
var ports []nat.Port
var ports []networktypes.Port
for port := range container.NetworkSettings.Ports {
ports = append(ports, port)
}
less := func(i, j nat.Port) bool {
return i.Int() < j.Int()
}
nat.Sort(ports, less)
slices.SortFunc(ports, func(a, b networktypes.Port) int {
return cmp.Compare(a.Num(), b.Num())
})
if len(ports) > 0 {
return ports[0].Port()
}
return ""
return ports[0].Port()
}
func getServiceName(container dockerData) string {

View File

@ -4,10 +4,9 @@ import (
"strconv"
"testing"
containertypes "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/go-connections/nat"
containertypes "github.com/moby/moby/api/types/container"
networktypes "github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -26,16 +25,16 @@ func Test_getPort_docker(t *testing.T) {
},
{
desc: "binding, no server port label",
container: containerJSON(ports(nat.PortMap{
"80/tcp": {},
container: containerJSON(ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): {},
})),
expected: "80",
},
{
desc: "binding, multiple ports, no server port label",
container: containerJSON(ports(nat.PortMap{
"80/tcp": {},
"443/tcp": {},
container: containerJSON(ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): {},
networktypes.MustParsePort("443/tcp"): {},
})),
expected: "80",
},
@ -48,17 +47,17 @@ func Test_getPort_docker(t *testing.T) {
{
desc: "binding, server port label",
container: containerJSON(
ports(nat.PortMap{
"80/tcp": {},
ports(networktypes.PortMap{
networktypes.MustParsePort("80/tcp"): {},
})),
serverPort: "8080",
expected: "8080",
},
{
desc: "binding, multiple ports, server port label",
container: containerJSON(ports(nat.PortMap{
"8080/tcp": {},
"80/tcp": {},
container: containerJSON(ports(networktypes.PortMap{
networktypes.MustParsePort("8080/tcp"): {},
networktypes.MustParsePort("80/tcp"): {},
})),
serverPort: "8080",
expected: "8080",

View File

@ -1,15 +1,18 @@
package ecs
import (
"cmp"
"context"
"errors"
"fmt"
"math"
"net"
"slices"
"strconv"
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
"github.com/docker/go-connections/nat"
networktypes "github.com/moby/moby/api/types/network"
"github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/label"
@ -309,26 +312,31 @@ func getPort(instance ecsInstance, serverPort string) string {
return serverPort
}
var ports []nat.Port
var ports []networktypes.Port
for _, port := range instance.machine.ports {
natPort, err := nat.NewPort(string(port.protocol), strconv.FormatInt(int64(port.hostPort), 10))
if err != nil {
if port.hostPort < 0 || port.hostPort > math.MaxUint16 {
// port out of range
continue
}
if port.protocol == "" {
port.protocol = ecstypes.TransportProtocolTcp
}
natPort, ok := networktypes.PortFrom(uint16(port.hostPort), networktypes.IPProtocol(port.protocol))
if !ok {
continue
}
ports = append(ports, natPort)
}
less := func(i, j nat.Port) bool {
return i.Int() < j.Int()
}
nat.Sort(ports, less)
if len(ports) > 0 {
return ports[0].Port()
if len(ports) == 0 {
return ""
}
return ""
slices.SortFunc(ports, func(a, b networktypes.Port) int {
return cmp.Compare(a.Num(), b.Num())
})
return ports[0].Port()
}
func getServiceName(instance ecsInstance) string {