From e6abf7c3c8ba8d216460f7eef1e937f00cb8e970 Mon Sep 17 00:00:00 2001 From: Romain Date: Mon, 4 May 2026 11:12:05 +0200 Subject: [PATCH 1/4] Remove cross-provider sanitization for Kubernetes service loading Co-authored-by: Gina A. <70909035+gndz07@users.noreply.github.com> --- .../with_error_page_traefik_service.yml | 29 ++++++++++ pkg/provider/kubernetes/crd/kubernetes.go | 32 +++++------ .../kubernetes/crd/kubernetes_http.go | 47 +++++++--------- .../kubernetes/crd/kubernetes_test.go | 54 +++++++++++++++++++ 4 files changed, 120 insertions(+), 42 deletions(-) create mode 100644 pkg/provider/kubernetes/crd/fixtures/with_error_page_traefik_service.yml diff --git a/pkg/provider/kubernetes/crd/fixtures/with_error_page_traefik_service.yml b/pkg/provider/kubernetes/crd/fixtures/with_error_page_traefik_service.yml new file mode 100644 index 000000000..4e3f18a8e --- /dev/null +++ b/pkg/provider/kubernetes/crd/fixtures/with_error_page_traefik_service.yml @@ -0,0 +1,29 @@ +apiVersion: traefik.io/v1alpha1 +kind: TraefikService +metadata: + name: errorpage-wrr + namespace: default + +spec: + weighted: + services: + - name: whoami + port: 80 + weight: 1 + +--- +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: errorpage + namespace: default + +spec: + errors: + status: + - "404" + - "500" + query: query + service: + name: errorpage-wrr + kind: TraefikService diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index a3f23d4ed..b785e81b9 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -243,16 +243,20 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) continue } - errorPage, errorPageService, err := p.createErrorPageMiddleware(client, middleware.Namespace, middleware.Spec.Errors) + errorPageName, errorPage, errorPageService, err := p.createErrorPageMiddleware(ctxMid, client, middleware.Namespace, middleware.Spec.Errors) if err != nil { log.FromContext(ctxMid).Errorf("Error while reading error page middleware: %v", err) continue } - if errorPage != nil && errorPageService != nil { - serviceName := id + "-errorpage-service" - errorPage.Service = serviceName - conf.HTTP.Services[serviceName] = errorPageService + if errorPage != nil { + if errorPageService != nil { + serviceName := id + "-errorpage-service" + errorPage.Service = serviceName + conf.HTTP.Services[serviceName] = errorPageService + } else { + errorPage.Service = errorPageName + } } plugin, err := createPluginMiddleware(client, middleware.Namespace, middleware.Spec.Plugin) @@ -617,14 +621,9 @@ func createRetryMiddleware(retry *traefikv1alpha1.Retry) (*dynamic.Retry, error) return r, nil } -func (p *Provider) createErrorPageMiddleware(client Client, namespace string, errorPage *traefikv1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) { +func (p *Provider) createErrorPageMiddleware(ctx context.Context, client Client, namespace string, errorPage *traefikv1alpha1.ErrorPage) (string, *dynamic.ErrorPage, *dynamic.Service, error) { if errorPage == nil { - return nil, nil, nil - } - - errorPageMiddleware := &dynamic.ErrorPage{ - Status: errorPage.Status, - Query: errorPage.Query, + return "", nil, nil, nil } cb := configBuilder{ @@ -634,12 +633,15 @@ func (p *Provider) createErrorPageMiddleware(client Client, namespace string, er allowEmptyServices: p.AllowEmptyServices, } - balancerServerHTTP, err := cb.buildServersLB(namespace, errorPage.Service.LoadBalancerSpec) + balancerName, balancerServerHTTP, err := cb.nameAndService(ctx, namespace, errorPage.Service.LoadBalancerSpec) if err != nil { - return nil, nil, err + return "", nil, nil, err } - return errorPageMiddleware, balancerServerHTTP, nil + return balancerName, &dynamic.ErrorPage{ + Status: errorPage.Status, + Query: errorPage.Query, + }, balancerServerHTTP, nil } func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *traefikv1alpha1.ForwardAuth) (*dynamic.ForwardAuth, error) { diff --git a/pkg/provider/kubernetes/crd/kubernetes_http.go b/pkg/provider/kubernetes/crd/kubernetes_http.go index ca429dd17..3dcf7112b 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_http.go +++ b/pkg/provider/kubernetes/crd/kubernetes_http.go @@ -293,8 +293,8 @@ func (c configBuilder) buildMirroring(ctx context.Context, tService *traefikv1al } // buildServersLB creates the configuration for the load-balancer of servers defined by svc. -func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.LoadBalancerSpec) (*dynamic.Service, error) { - servers, err := c.loadServers(namespace, svc) +func (c configBuilder) buildServersLB(svc traefikv1alpha1.LoadBalancerSpec) (*dynamic.Service, error) { + servers, err := c.loadServers(svc) if err != nil { return nil, err } @@ -313,7 +313,7 @@ func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.Load lb.Sticky = svc.Sticky - lb.ServersTransport, err = c.makeServersTransportKey(namespace, svc.ServersTransport) + lb.ServersTransport, err = c.makeServersTransportKey(svc.Namespace, svc.ServersTransport) if err != nil { return nil, err } @@ -340,7 +340,7 @@ func (c configBuilder) makeServersTransportKey(parentNamespace string, serversTr return provider.Normalize(makeID(parentNamespace, serversTransportName)), nil } -func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.LoadBalancerSpec) ([]dynamic.Server, error) { +func (c configBuilder) loadServers(svc traefikv1alpha1.LoadBalancerSpec) ([]dynamic.Server, error) { strategy := svc.Strategy if strategy == "" { strategy = roundRobinStrategy @@ -349,20 +349,12 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L return nil, fmt.Errorf("load balancing strategy %s is not supported", strategy) } - namespace := namespaceOrFallback(svc, parentNamespace) - - if !isNamespaceAllowed(c.allowCrossNamespace, parentNamespace, namespace) { - return nil, fmt.Errorf("load balancer service %s/%s is not in the parent resource namespace %s", svc.Namespace, svc.Name, parentNamespace) - } - - // If the service uses explicitly the provider suffix - sanitizedName := strings.TrimSuffix(svc.Name, providerNamespaceSeparator+providerName) - service, exists, err := c.client.GetService(namespace, sanitizedName) + service, exists, err := c.client.GetService(svc.Namespace, svc.Name) if err != nil { return nil, err } if !exists { - return nil, fmt.Errorf("kubernetes service not found: %s/%s", namespace, sanitizedName) + return nil, fmt.Errorf("kubernetes service not found: %s/%s", svc.Namespace, svc.Name) } svcPort, err := getServicePort(service, svc.Port) @@ -387,7 +379,7 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L var servers []dynamic.Server if service.Spec.Type == corev1.ServiceTypeExternalName { if !c.allowExternalNameServices { - return nil, fmt.Errorf("externalName services not allowed: %s/%s", namespace, sanitizedName) + return nil, fmt.Errorf("externalName services not allowed: %s/%s", svc.Namespace, svc.Name) } protocol, err := parseServiceProtocol(svc.Scheme, svcPort.Name, svcPort.Port) @@ -402,16 +394,16 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L }), nil } - endpoints, endpointsExists, endpointsErr := c.client.GetEndpoints(namespace, sanitizedName) + endpoints, endpointsExists, endpointsErr := c.client.GetEndpoints(svc.Namespace, svc.Name) if endpointsErr != nil { return nil, endpointsErr } if !endpointsExists { - return nil, fmt.Errorf("endpoints not found for %s/%s", namespace, sanitizedName) + return nil, fmt.Errorf("endpoints not found for %s/%s", svc.Namespace, svc.Name) } if len(endpoints.Subsets) == 0 && !c.allowEmptyServices { - return nil, fmt.Errorf("subset not found for %s/%s", namespace, sanitizedName) + return nil, fmt.Errorf("subset not found for %s/%s", svc.Namespace, svc.Name) } for _, subset := range endpoints.Subsets { @@ -451,25 +443,26 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L func (c configBuilder) nameAndService(ctx context.Context, parentNamespace string, service traefikv1alpha1.LoadBalancerSpec) (string, *dynamic.Service, error) { svcCtx := log.With(ctx, log.Str(log.ServiceName, service.Name)) - namespace := namespaceOrFallback(service, parentNamespace) + service = *service.DeepCopy() + service.Namespace = namespaceOrFallback(service, parentNamespace) - if !isNamespaceAllowed(c.allowCrossNamespace, parentNamespace, namespace) { + if !isNamespaceAllowed(c.allowCrossNamespace, parentNamespace, service.Namespace) { return "", nil, fmt.Errorf("service %s/%s not in the parent resource namespace %s", service.Namespace, service.Name, parentNamespace) } switch service.Kind { case "", "Service": - serversLB, err := c.buildServersLB(namespace, service) + serversLB, err := c.buildServersLB(service) if err != nil { return "", nil, err } - fullName := fullServiceName(svcCtx, namespace, service, service.Port) + fullName := fullServiceName(svcCtx, service, service.Port) return fullName, serversLB, nil case "TraefikService": - return fullServiceName(svcCtx, namespace, service, intstr.FromInt(0)), nil, nil + return fullServiceName(svcCtx, service, intstr.FromInt(0)), nil, nil default: return "", nil, fmt.Errorf("unsupported service kind %s", service.Kind) @@ -485,18 +478,18 @@ func splitSvcNameProvider(name string) (string, string) { return svc, pvd } -func fullServiceName(ctx context.Context, namespace string, service traefikv1alpha1.LoadBalancerSpec, port intstr.IntOrString) string { +func fullServiceName(ctx context.Context, service traefikv1alpha1.LoadBalancerSpec, port intstr.IntOrString) string { if (port.Type == intstr.Int && port.IntVal != 0) || (port.Type == intstr.String && port.StrVal != "") { - return provider.Normalize(fmt.Sprintf("%s-%s-%s", namespace, service.Name, &port)) + return provider.Normalize(fmt.Sprintf("%s-%s-%s", service.Namespace, service.Name, &port)) } if !strings.Contains(service.Name, providerNamespaceSeparator) { - return provider.Normalize(fmt.Sprintf("%s-%s", namespace, service.Name)) + return provider.Normalize(fmt.Sprintf("%s-%s", service.Namespace, service.Name)) } name, pName := splitSvcNameProvider(service.Name) if pName == providerName { - return provider.Normalize(fmt.Sprintf("%s-%s", namespace, name)) + return provider.Normalize(fmt.Sprintf("%s-%s", service.Namespace, name)) } if service.Namespace != "" { diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index 526b0e73d..1d64d3fd6 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -3596,6 +3596,60 @@ func TestLoadIngressRoutes(t *testing.T) { }, }, }, + { + desc: "Error page middleware referencing a TraefikService", + paths: []string{"services.yml", "with_error_page_traefik_service.yml"}, + expected: &dynamic.Configuration{ + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{}, + Services: map[string]*dynamic.UDPService{}, + }, + TLS: &dynamic.TLSConfiguration{}, + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{}, + Middlewares: map[string]*dynamic.Middleware{ + "default-errorpage": { + Errors: &dynamic.ErrorPage{ + Status: []string{"404", "500"}, + Service: "default-errorpage-wrr", + Query: "query", + }, + }, + }, + Services: map[string]*dynamic.Service{ + "default-errorpage-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: pointer(true), + }, + }, + }, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, { desc: "Simple Ingress Route, with options", paths: []string{"services.yml", "with_options.yml"}, From 29d2340ca405c50d95a6996e2d1599206c71f0e2 Mon Sep 17 00:00:00 2001 From: "Gina A." <70909035+gndz07@users.noreply.github.com> Date: Mon, 4 May 2026 19:54:05 +0700 Subject: [PATCH 2/4] Bump Axios version --- .github/workflows/template-webui.yaml | 2 +- webui/package.json | 2 +- webui/yarn.lock | 32 +++++++++++++-------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/template-webui.yaml b/.github/workflows/template-webui.yaml index 05ff981a9..ca675b30a 100644 --- a/.github/workflows/template-webui.yaml +++ b/.github/workflows/template-webui.yaml @@ -2,7 +2,7 @@ name: Build Web UI on: workflow_call: {} env: - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 360 # 15 days + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 48 # 2 days jobs: build-webui: diff --git a/webui/package.json b/webui/package.json index 0b5eb6624..a1e0b5ae0 100644 --- a/webui/package.json +++ b/webui/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@quasar/extras": "^1.16.12", - "axios": "1.13.2", + "axios": "1.15.1", "chart.js": "^4.4.1", "core-js": "^3.35.1", "dot-prop": "^8.0.2", diff --git a/webui/yarn.lock b/webui/yarn.lock index ad0e8d0d5..0c6ee58cb 100644 --- a/webui/yarn.lock +++ b/webui/yarn.lock @@ -2163,14 +2163,14 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" -axios@1.13.2: - version "1.13.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.2.tgz#9ada120b7b5ab24509553ec3e40123521117f687" - integrity sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA== +axios@1.15.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.15.1.tgz#075420b785da8adbdf545785b69f90c926b28542" + integrity sha512-WOG+Jj8ZOvR0a3rAn+Tuf1UQJRxw5venr6DgdbJzngJE3qG7X0kL83CZGpdHMxEm+ZK3seAbvFsw4FfOfP9vxg== dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.4" - proxy-from-env "^1.1.0" + follow-redirects "^1.15.11" + form-data "^4.0.5" + proxy-from-env "^2.1.0" b4a@^1.6.4: version "1.6.7" @@ -3580,10 +3580,10 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== -follow-redirects@^1.15.6: - version "1.15.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" - integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== +follow-redirects@^1.15.11: + version "1.16.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.16.0.tgz#28474a159d3b9d11ef62050a14ed60e4df6d61bc" + integrity sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw== for-each@^0.3.3: version "0.3.3" @@ -3600,7 +3600,7 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" -form-data@^4.0.4: +form-data@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== @@ -5080,10 +5080,10 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +proxy-from-env@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba" + integrity sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA== punycode@^2.1.0: version "2.3.1" From e4537f8b04c5b8496870752557f7d1a7b65fe420 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 4 May 2026 16:06:05 +0200 Subject: [PATCH 3/4] Migrate to github.com/moby/moby modules --- docs/content/migration/v2.md | 10 + go.mod | 37 ++- go.sum | 97 +++---- integration/integration_test.go | 19 +- integration/k8s_test.go | 58 +++-- integration/resources/compose/k8s.yml | 34 --- pkg/provider/docker/builder_test.go | 59 +++-- pkg/provider/docker/config.go | 47 ++-- pkg/provider/docker/config_test.go | 361 +++++++++++++------------- pkg/provider/docker/docker.go | 131 +++++----- pkg/provider/docker/swarm_test.go | 117 +++++---- pkg/provider/ecs/config.go | 34 ++- 12 files changed, 491 insertions(+), 513 deletions(-) delete mode 100644 integration/resources/compose/k8s.yml diff --git a/docs/content/migration/v2.md b/docs/content/migration/v2.md index 0ea315fc0..3dd6b2052 100644 --- a/docs/content/migration/v2.md +++ b/docs/content/migration/v2.md @@ -813,3 +813,13 @@ By default, the behavior is unchanged: all original request headers are forwarde If the error page service is in a separate trust domain, consider using `errorRequestHeaders` to restrict which headers are forwarded. Please check out the [Error Pages](../middlewares/http/errorpages.md#forwardheaders) middleware documentation for more details. + +## v2.11.45 + +### Docker provider: minimum Docker Engine version + +Starting with `v2.11.45`, 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. diff --git a/go.mod b/go.mod index ba2553670..cc56298a0 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.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 @@ -38,7 +37,7 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.7.0 github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab // No tag on the repo. github.com/instana/go-sensor v1.38.3 - github.com/klauspost/compress v1.18.0 + github.com/klauspost/compress v1.18.5 github.com/kvtools/consul v1.0.2 github.com/kvtools/etcdv3 v1.0.2 github.com/kvtools/redis v1.1.0 @@ -49,6 +48,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 + github.com/moby/moby/api v1.54.1 + github.com/moby/moby/client v0.4.0 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // No tag on the repo. github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 github.com/openzipkin/zipkin-go v0.2.5 @@ -59,10 +60,10 @@ require ( github.com/prometheus/client_model v0.6.1 github.com/quic-go/quic-go v0.57.1 github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac // No tag on the repo. - github.com/sirupsen/logrus v1.9.3 + github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 // No tag on the repo. - github.com/testcontainers/testcontainers-go v0.32.0 + github.com/testcontainers/testcontainers-go v0.42.0 github.com/traefik/paerser v0.2.2 github.com/traefik/yaegi v0.16.1 github.com/uber/jaeger-client-go v2.30.0+incompatible @@ -94,7 +95,7 @@ require ( cloud.google.com/go/auth v0.20.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect - dario.cat/mergo v1.0.1 // indirect + dario.cat/mergo v1.0.2 // indirect github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 // indirect @@ -135,7 +136,6 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Microsoft/hcsshim v0.13.0 // indirect github.com/VividCortex/gohistogram v1.0.0 // indirect github.com/akamai/AkamaiOPEN-edgegrid-golang/v13 v13.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect @@ -169,13 +169,12 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect - github.com/containerd/containerd v1.7.29 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v1.0.0-rc.1 // indirect github.com/coreos/go-semver v0.3.0 // indirect - github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deepmap/oapi-codegen v1.9.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -186,7 +185,7 @@ require ( github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect - github.com/ebitengine/purego v0.8.3 // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/elastic/go-sysinfo v1.7.1 // indirect github.com/elastic/go-windows v1.0.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect @@ -272,7 +271,7 @@ require ( github.com/liquidweb/liquidweb-go v1.6.4 // indirect github.com/looplab/fsm v0.1.0 // indirect github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect - github.com/magiconair/properties v1.8.7 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f // indirect github.com/mailgun/multibuf v0.1.2 // indirect github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 // indirect @@ -283,16 +282,14 @@ require ( github.com/mitchellh/go-homedir v1.1.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/sys/atomicwriter v0.1.0 // indirect + github.com/moby/go-archive v0.2.0 // indirect + github.com/moby/patternmatcher v0.6.1 // indirect github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/user v0.4.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect 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/namedotcom/go/v4 v4.0.2 // indirect github.com/nrdcg/auroradns v1.2.0 // indirect @@ -342,9 +339,7 @@ require ( github.com/segmentio/fasthash v1.0.3 // indirect github.com/selectel/domains-go v1.1.0 // indirect github.com/selectel/go-selvpcclient/v4 v4.2.0 // indirect - github.com/shirou/gopsutil/v3 v3.24.4 // indirect - github.com/shirou/gopsutil/v4 v4.25.3 // indirect - github.com/shoenig/go-m1cpu v0.1.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 @@ -357,10 +352,11 @@ require ( github.com/stretchr/objx v0.5.3 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.83 // indirect + github.com/testcontainers/testcontainers-go/modules/k3s v0.42.0 github.com/tinylib/msgp v1.2.5 // 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 @@ -396,6 +392,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect go.uber.org/zap v1.27.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.50.0 // indirect golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect golang.org/x/oauth2 v0.36.0 // indirect diff --git a/go.sum b/go.sum index 271b427e8..b4d649001 100644 --- a/go.sum +++ b/go.sum @@ -598,8 +598,8 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= @@ -720,8 +720,6 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA= -github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH6HAaclpEok= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -929,8 +927,6 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE= -github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -960,16 +956,16 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= -github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/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= @@ -993,10 +989,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= @@ -1019,8 +1013,8 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg= github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds= -github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc= -github.com/ebitengine/purego v0.8.3/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= @@ -1393,12 +1387,9 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= @@ -1568,8 +1559,8 @@ github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= @@ -1631,7 +1622,6 @@ github.com/liquidweb/liquidweb-go v1.6.4/go.mod h1:B934JPIIcdA+uTq2Nz5PgOtG6CuCa github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/looplab/fsm v0.1.0 h1:Qte7Zdn/5hBNbXzP7yxVU4OIFHWXBovyTT2LaBTyC20= github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/uafI= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= @@ -1641,8 +1631,9 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailgun/multibuf v0.1.2 h1:QE9kE27lK6LFZB4aYNVtUPlWVHVCT0zpgUr2uoq/+jk= github.com/mailgun/multibuf v0.1.2/go.mod h1:E+sUhIy69qgT6EM57kCPdUTlHnjTuxQBO/yf6af9Hes= github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ= @@ -1730,13 +1721,15 @@ 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.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -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= @@ -1755,8 +1748,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-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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= @@ -1906,7 +1897,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= @@ -2009,13 +1999,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/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU= -github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8= -github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE= -github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= -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= +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= @@ -2028,8 +2013,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= @@ -2104,7 +2089,6 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 h1:XGopsea1Dw7ecQ8JscCNQXDGYAKDiWjDeXnpN/+BY9g= @@ -2117,19 +2101,19 @@ 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.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= -github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= +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/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= 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.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -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.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -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-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ= @@ -2288,10 +2272,6 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:Oyrsyzu go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= go.opentelemetry.io/otel/log v0.11.0 h1:c24Hrlk5WJ8JWcwbQxdBqxZdOK7PcP/LFtOtwpDTe3Y= go.opentelemetry.io/otel/log v0.11.0/go.mod h1:U/sxQ83FPmT29trrifhQg+Zj2lo1/IPN1PF6RTFqdwc= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= @@ -2305,8 +2285,6 @@ go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLh go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -2335,6 +2313,8 @@ go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -2707,7 +2687,6 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc 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-20220627191245-f75cf1eec38b/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= @@ -2722,14 +2701,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.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.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= @@ -3308,6 +3285,8 @@ modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8= mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= +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= diff --git a/integration/integration_test.go b/integration/integration_test.go index 12861fd47..c07b7f7ff 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -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/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/testcontainers/testcontainers-go" @@ -37,7 +39,10 @@ import ( var showLog = flag.Bool("tlog", false, "always show Traefik logs") -const tailscaleSecretFilePath = "tailscale.secret" +const ( + tailscaleSecretFilePath = "tailscale.secret" + k3sImage = "docker.io/rancher/k3s:v1.21.14-k3s1" +) type composeConfig struct { Services map[string]composeService `yaml:"services"` @@ -87,7 +92,7 @@ func (s *BaseSuite) SetupSuite() { Driver: "default", Config: []dockernetwork.IPAMConfig{ { - Subnet: "172.31.42.0/24", + Subnet: netip.MustParsePrefix("172.31.42.0/24"), }, }, })) @@ -140,12 +145,12 @@ func isDockerDesktop(ctx context.Context, t *testing.T) bool { t.Fatalf("failed to create docker client: %s", err) } - info, err := cli.Info(ctx) + res, err := cli.Info(ctx, 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() { diff --git a/integration/k8s_test.go b/integration/k8s_test.go index 1d50b5a59..2ace67637 100644 --- a/integration/k8s_test.go +++ b/integration/k8s_test.go @@ -7,18 +7,18 @@ import ( "flag" "fmt" "io" - "net" "net/http" "os" "path/filepath" "regexp" - "strings" "testing" "time" "github.com/pmezard/go-difflib/difflib" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/modules/k3s" "github.com/traefik/traefik/v2/integration/try" "github.com/traefik/traefik/v2/pkg/api" "github.com/traefik/traefik/v2/pkg/log" @@ -27,7 +27,11 @@ import ( var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata") // K8sSuite tests suite. -type K8sSuite struct{ BaseSuite } +type K8sSuite struct { + BaseSuite + + k3sContainer *k3s.K3sContainer +} func TestK8sSuite(t *testing.T) { suite.Run(t, new(K8sSuite)) @@ -36,47 +40,45 @@ func TestK8sSuite(t *testing.T) { func (s *K8sSuite) SetupSuite() { s.BaseSuite.SetupSuite() - s.createComposeProject("k8s") - s.composeUp() - - abs, err := filepath.Abs("./fixtures/k8s/config.skip/kubeconfig.yaml") + manifests, err := filepath.Glob("./fixtures/k8s/*.yml") require.NoError(s.T(), err) - err = try.Do(60*time.Second, func() error { - _, err := os.Stat(abs) - return err - }) + opts := make([]testcontainers.ContainerCustomizer, 0, len(manifests)) + for _, m := range manifests { + opts = append(opts, k3s.WithManifest(m)) + } + + s.k3sContainer, err = k3s.Run(s.T().Context(), k3sImage, opts...) require.NoError(s.T(), err) - data, err := os.ReadFile(abs) + kubeConfigYaml, err := s.k3sContainer.GetKubeConfig(s.T().Context()) 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) + kubeconfigPath := filepath.Join(s.T().TempDir(), "kubeconfig.yaml") + err = os.WriteFile(kubeconfigPath, kubeConfigYaml, 0o644) require.NoError(s.T(), err) - err = os.Setenv("KUBECONFIG", abs) + err = os.Setenv("KUBECONFIG", kubeconfigPath) require.NoError(s.T(), err) } func (s *K8sSuite) TearDownSuite() { - s.BaseSuite.TearDownSuite() + if s.k3sContainer != nil { + if s.T().Failed() || *showLog { + k3sLogs, err := s.k3sContainer.Logs(s.T().Context()) + if err == nil { + if res, err := io.ReadAll(k3sLogs); err == nil { + s.T().Log(string(res)) + } + } + } - generatedFiles := []string{ - "./fixtures/k8s/config.skip/kubeconfig.yaml", - "./fixtures/k8s/config.skip/k3s.log", - "./fixtures/k8s/coredns.yaml", - "./fixtures/k8s/rolebindings.yaml", - "./fixtures/k8s/traefik.yaml", - "./fixtures/k8s/ccm.yaml", - } - - for _, filename := range generatedFiles { - if err := os.Remove(filename); err != nil { + if err := s.k3sContainer.Terminate(s.T().Context()); err != nil { log.WithoutContext().Warning(err) } } + + s.BaseSuite.TearDownSuite() } func (s *K8sSuite) TestIngressConfiguration() { diff --git a/integration/resources/compose/k8s.yml b/integration/resources/compose/k8s.yml deleted file mode 100644 index a34f72bd7..000000000 --- a/integration/resources/compose/k8s.yml +++ /dev/null @@ -1,34 +0,0 @@ -version: "3.8" -services: - server: - image: rancher/k3s:v1.20.15-k3s1 - privileged: true - command: - - server - - --disable-agent - - --disable=coredns - - --disable=servicelb - - --disable=traefik - - --disable=local-storage - - --disable=metrics-server - - --log=/output/k3s.log - - --bind-address=server - - --tls-san=server - - --tls-san=172.31.42.3 - - --tls-san=172.31.42.4 - environment: - K3S_CLUSTER_SECRET: somethingtotallyrandom - K3S_TOKEN: somethingtotallyrandom - K3S_KUBECONFIG_OUTPUT: /output/kubeconfig.yaml - K3S_KUBECONFIG_MODE: 666 - volumes: - - ./fixtures/k8s/config.skip:/output - - ./fixtures/k8s:/var/lib/rancher/k3s/server/manifests - - node: - image: rancher/k3s:v1.20.15-k3s1 - privileged: true - environment: - K3S_TOKEN: somethingtotallyrandom - K3S_URL: https://server:6443 - K3S_CLUSTER_SECRET: somethingtotallyrandom diff --git a/pkg/provider/docker/builder_test.go b/pkg/provider/docker/builder_test.go index 77dad2b57..47bfaaa2a 100644 --- a/pkg/provider/docker/builder_test.go +++ b/pkg/provider/docker/builder_test.go @@ -1,18 +1,17 @@ package docker import ( - dockercontainertypes "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/network" - "github.com/docker/docker/api/types/swarm" - "github.com/docker/go-connections/nat" + "net/netip" + + dockercontainertypes "github.com/moby/moby/api/types/container" + "github.com/moby/moby/api/types/network" + "github.com/moby/moby/api/types/swarm" ) func containerJSON(ops ...func(*dockercontainertypes.InspectResponse)) dockercontainertypes.InspectResponse { c := &dockercontainertypes.InspectResponse{ - ContainerJSONBase: &dockercontainertypes.ContainerJSONBase{ - Name: "fake", - HostConfig: &dockercontainertypes.HostConfig{}, - }, + Name: "fake", + HostConfig: &dockercontainertypes.HostConfig{}, Config: &dockercontainertypes.Config{}, NetworkSettings: &dockercontainertypes.NetworkSettings{}, } @@ -26,17 +25,17 @@ func containerJSON(ops ...func(*dockercontainertypes.InspectResponse)) dockercon func name(name string) func(*dockercontainertypes.InspectResponse) { return func(c *dockercontainertypes.InspectResponse) { - c.ContainerJSONBase.Name = name + c.Name = name } } func networkMode(mode string) func(*dockercontainertypes.InspectResponse) { return func(c *dockercontainertypes.InspectResponse) { - c.ContainerJSONBase.HostConfig.NetworkMode = dockercontainertypes.NetworkMode(mode) + c.HostConfig.NetworkMode = dockercontainertypes.NetworkMode(mode) } } -func ports(portMap nat.PortMap) func(*dockercontainertypes.InspectResponse) { +func ports(portMap network.PortMap) func(*dockercontainertypes.InspectResponse) { return func(c *dockercontainertypes.InspectResponse) { c.NetworkSettings.Ports = portMap } @@ -56,13 +55,13 @@ func withNetwork(name string, ops ...func(*network.EndpointSettings)) func(*dock func ipv4(ip string) func(*network.EndpointSettings) { return func(s *network.EndpointSettings) { - s.IPAddress = ip + s.IPAddress = netip.MustParseAddr(ip).Unmap() } } func ipv6(ip string) func(*network.EndpointSettings) { return func(s *network.EndpointSettings) { - s.GlobalIPv6Address = ip + s.GlobalIPv6Address = netip.MustParseAddr(ip) } } @@ -91,20 +90,20 @@ func taskNodeID(id string) func(*swarm.Task) { } func taskNetworkAttachment(id, name, driver string, addresses []string) func(*swarm.Task) { + prefixes := make([]netip.Prefix, len(addresses)) + for i, s := range addresses { + prefixes[i] = mustParseAddrOrPrefix(s) + } return func(task *swarm.Task) { task.NetworksAttachments = append(task.NetworksAttachments, swarm.NetworkAttachment{ Network: swarm.Network{ ID: id, Spec: swarm.NetworkSpec{ - Annotations: swarm.Annotations{ - Name: name, - }, - DriverConfiguration: &swarm.Driver{ - Name: driver, - }, + Annotations: swarm.Annotations{Name: name}, + DriverConfiguration: &swarm.Driver{Name: driver}, }, }, - Addresses: addresses, + Addresses: prefixes, }) } } @@ -183,7 +182,7 @@ func virtualIP(networkID, addr string) func(*swarm.Endpoint) { } endpoint.VirtualIPs = append(endpoint.VirtualIPs, swarm.EndpointVirtualIP{ NetworkID: networkID, - Addr: addr, + Addr: mustParseAddrOrPrefix(addr), }) } } @@ -207,3 +206,21 @@ func modeDNSRR(spec *swarm.EndpointSpec) { func modeVIP(spec *swarm.EndpointSpec) { spec.Mode = swarm.ResolutionModeVIP } + +// mustParseAddrOrPrefix parses addrOrPrefix into a [netip.Prefix]. +// +// We should expect only IP-addresses, but for backwards-compatibility, +// the Addresses field on [swarm.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) +} diff --git a/pkg/provider/docker/config.go b/pkg/provider/docker/config.go index b159df92c..ead45f19f 100644 --- a/pkg/provider/docker/config.go +++ b/pkg/provider/docker/config.go @@ -1,14 +1,17 @@ package docker import ( + "cmp" "context" "errors" "fmt" "net" + "slices" "strings" - dockertypes "github.com/docker/docker/api/types" - "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/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/config/label" "github.com/traefik/traefik/v2/pkg/log" @@ -103,7 +106,7 @@ func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, container d } } - if container.Health != "" && container.Health != dockertypes.Healthy { + if container.Health != "" && container.Health != string(containertypes.Healthy) { return nil } @@ -127,7 +130,7 @@ func (p *Provider) buildUDPServiceConfiguration(ctx context.Context, container d } } - if container.Health != "" && container.Health != dockertypes.Healthy { + if container.Health != "" && container.Health != string(containertypes.Healthy) { return nil } @@ -153,7 +156,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, container dock } } - if container.Health != "" && container.Health != dockertypes.Healthy { + if container.Health != "" && container.Health != string(containertypes.Healthy) { return nil } @@ -185,7 +188,7 @@ func (p *Provider) keepContainer(ctx context.Context, container dockerData) bool return false } - if !p.AllowEmptyServices && container.Health != "" && container.Health != dockertypes.Healthy { + if !p.AllowEmptyServices && container.Health != "" && container.Health != string(containertypes.Healthy) { logger.Debug("Filtering unhealthy or starting container") return false } @@ -286,10 +289,10 @@ func (p *Provider) getIPPort(ctx context.Context, container dockerData, serverPo switch { case err != nil: logger.Infof("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.Infof("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 } @@ -345,7 +348,7 @@ func (p *Provider) getIPAddress(ctx context.Context, container dockerData) strin } connectedContainer := container.NetworkSettings.NetworkMode.ConnectedContainer() - containerInspected, err := dockerClient.ContainerInspect(context.Background(), connectedContainer) + res, err := dockerClient.ContainerInspect(context.Background(), connectedContainer, client.ContainerInspectOptions{}) if err != nil { logger.Warnf("Unable to get IP address for container %s : Failed to inspect container ID %s, error: %s", container.Name, connectedContainer, err) return "" @@ -353,10 +356,10 @@ func (p *Provider) getIPAddress(ctx context.Context, container dockerData) strin // 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.getConfiguration(containerParsed) if err != nil { - logger.Warnf("Unable to get IP address for container %s : failed to get extra configuration for container %s: %s", container.Name, containerInspected.Name, err) + logger.Warnf("Unable to get IP address for container %s : failed to get extra configuration for container %s: %s", container.Name, res.Container.Name, err) return "" } @@ -379,10 +382,10 @@ func (p *Provider) getIPAddress(ctx context.Context, container dockerData) strin return "" } -func (p *Provider) getPortBinding(container dockerData, serverPort string) (*nat.PortBinding, error) { +func (p *Provider) 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 } @@ -396,22 +399,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 { diff --git a/pkg/provider/docker/config_test.go b/pkg/provider/docker/config_test.go index 831f565a2..c1686cf6b 100644 --- a/pkg/provider/docker/config_test.go +++ b/pkg/provider/docker/config_test.go @@ -1,14 +1,13 @@ package docker import ( + "net/netip" "strconv" "testing" - docker "github.com/docker/docker/api/types" - dockercontainertypes "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" + dockercontainertypes "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" "github.com/traefik/traefik/v2/pkg/config/dynamic" @@ -31,8 +30,8 @@ func TestDefaultRule(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": { @@ -90,8 +89,8 @@ func TestDefaultRule(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": { @@ -151,8 +150,8 @@ func TestDefaultRule(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": { @@ -210,8 +209,8 @@ func TestDefaultRule(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": { @@ -263,8 +262,8 @@ func TestDefaultRule(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": { @@ -316,8 +315,8 @@ func TestDefaultRule(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": { @@ -413,8 +412,8 @@ func Test_buildConfiguration(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": { @@ -456,8 +455,8 @@ func Test_buildConfiguration(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": { @@ -499,8 +498,8 @@ func Test_buildConfiguration(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": { @@ -540,8 +539,8 @@ func Test_buildConfiguration(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": { @@ -598,8 +597,8 @@ func Test_buildConfiguration(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": { @@ -614,8 +613,8 @@ func Test_buildConfiguration(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": { @@ -688,8 +687,8 @@ func Test_buildConfiguration(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": { @@ -705,8 +704,8 @@ func Test_buildConfiguration(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": { @@ -768,8 +767,8 @@ func Test_buildConfiguration(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": { @@ -830,8 +829,8 @@ func Test_buildConfiguration(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": { @@ -889,8 +888,8 @@ func Test_buildConfiguration(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": { @@ -949,8 +948,8 @@ func Test_buildConfiguration(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": { @@ -1010,8 +1009,8 @@ func Test_buildConfiguration(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": { @@ -1075,8 +1074,8 @@ func Test_buildConfiguration(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": { @@ -1135,8 +1134,8 @@ func Test_buildConfiguration(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": { @@ -1154,8 +1153,8 @@ func Test_buildConfiguration(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": { @@ -1204,8 +1203,8 @@ func Test_buildConfiguration(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": { @@ -1223,8 +1222,8 @@ func Test_buildConfiguration(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": { @@ -1242,8 +1241,8 @@ func Test_buildConfiguration(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": { @@ -1292,8 +1291,8 @@ func Test_buildConfiguration(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": { @@ -1311,8 +1310,8 @@ func Test_buildConfiguration(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": { @@ -1374,8 +1373,8 @@ func Test_buildConfiguration(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": { @@ -1441,8 +1440,8 @@ func Test_buildConfiguration(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": { @@ -1460,8 +1459,8 @@ func Test_buildConfiguration(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": { @@ -1530,8 +1529,8 @@ func Test_buildConfiguration(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": { @@ -1549,8 +1548,8 @@ func Test_buildConfiguration(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": { @@ -1613,8 +1612,8 @@ func Test_buildConfiguration(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": { @@ -1632,8 +1631,8 @@ func Test_buildConfiguration(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": { @@ -1651,8 +1650,8 @@ func Test_buildConfiguration(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": { @@ -1718,8 +1717,8 @@ func Test_buildConfiguration(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": { @@ -1737,8 +1736,8 @@ func Test_buildConfiguration(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": { @@ -1795,8 +1794,8 @@ func Test_buildConfiguration(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": { @@ -1814,8 +1813,8 @@ func Test_buildConfiguration(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": { @@ -1833,8 +1832,8 @@ func Test_buildConfiguration(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": { @@ -1894,8 +1893,8 @@ func Test_buildConfiguration(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": { @@ -1913,8 +1912,8 @@ func Test_buildConfiguration(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": { @@ -1975,8 +1974,8 @@ func Test_buildConfiguration(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": { @@ -1993,8 +1992,8 @@ func Test_buildConfiguration(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": { @@ -2057,8 +2056,8 @@ func Test_buildConfiguration(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": { @@ -2118,8 +2117,8 @@ func Test_buildConfiguration(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": { @@ -2179,8 +2178,8 @@ func Test_buildConfiguration(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": { @@ -2241,7 +2240,7 @@ func Test_buildConfiguration(t *testing.T) { Name: "Test", Labels: map[string]string{}, NetworkSettings: networkSettings{ - Ports: nat.PortMap{}, + Ports: networktypes.PortMap{}, Networks: map[string]*networkData{ "bridge": { Name: "bridge", @@ -2282,7 +2281,7 @@ func Test_buildConfiguration(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", @@ -2323,8 +2322,8 @@ func Test_buildConfiguration(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": { @@ -2362,7 +2361,7 @@ func Test_buildConfiguration(t *testing.T) { { ServiceName: "Test", Name: "Test", - Health: docker.Unhealthy, + Health: string(dockercontainertypes.Unhealthy), }, }, expected: &dynamic.Configuration{ @@ -2393,7 +2392,7 @@ func Test_buildConfiguration(t *testing.T) { { ServiceName: "Test", Name: "Test", - Health: docker.Unhealthy, + Health: string(dockercontainertypes.Unhealthy), }, }, expected: &dynamic.Configuration{ @@ -2435,7 +2434,7 @@ func Test_buildConfiguration(t *testing.T) { { ServiceName: "Test", Name: "Test", - Health: docker.Unhealthy, + Health: string(dockercontainertypes.Unhealthy), Labels: map[string]string{ "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", }, @@ -2469,7 +2468,7 @@ func Test_buildConfiguration(t *testing.T) { { ServiceName: "Test", Name: "Test", - Health: docker.Unhealthy, + Health: string(dockercontainertypes.Unhealthy), Labels: map[string]string{ "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", }, @@ -2513,7 +2512,7 @@ func Test_buildConfiguration(t *testing.T) { { ServiceName: "Test", Name: "Test", - Health: docker.Unhealthy, + Health: string(dockercontainertypes.Unhealthy), Labels: map[string]string{ "traefik.udp.routers.foo": "true", }, @@ -2550,7 +2549,7 @@ func Test_buildConfiguration(t *testing.T) { Labels: map[string]string{ "traefik.udp.routers.foo": "true", }, - Health: docker.Unhealthy, + Health: string(dockercontainertypes.Unhealthy), }, }, expected: &dynamic.Configuration{ @@ -2592,8 +2591,8 @@ func Test_buildConfiguration(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": { @@ -2636,8 +2635,8 @@ func Test_buildConfiguration(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": { @@ -2698,8 +2697,8 @@ func Test_buildConfiguration(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": { @@ -2770,8 +2769,8 @@ func Test_buildConfiguration(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": { @@ -2837,8 +2836,8 @@ func Test_buildConfiguration(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": { @@ -2897,8 +2896,8 @@ func Test_buildConfiguration(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": { @@ -2955,8 +2954,8 @@ func Test_buildConfiguration(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": { @@ -3011,8 +3010,8 @@ func Test_buildConfiguration(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": { @@ -3074,8 +3073,8 @@ func Test_buildConfiguration(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": { @@ -3134,8 +3133,8 @@ func Test_buildConfiguration(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": { @@ -3155,8 +3154,8 @@ func Test_buildConfiguration(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": { @@ -3236,8 +3235,8 @@ func Test_buildConfiguration(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": { @@ -3290,8 +3289,8 @@ func Test_buildConfiguration(t *testing.T) { "traefik.tcp.services.foo.loadbalancer.terminationdelay": "200", }, 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": { @@ -3344,13 +3343,13 @@ func Test_buildConfiguration(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", }}, }, @@ -3414,13 +3413,13 @@ func Test_buildConfiguration(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", }}, }, @@ -3527,8 +3526,8 @@ func TestDockerGetIPPort(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{ @@ -3540,8 +3539,8 @@ func TestDockerGetIPPort(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", }, @@ -3556,10 +3555,10 @@ func TestDockerGetIPPort(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", }, }, @@ -3582,10 +3581,10 @@ func TestDockerGetIPPort(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", }, }, @@ -3600,10 +3599,10 @@ func TestDockerGetIPPort(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", }, }, @@ -3618,16 +3617,16 @@ func TestDockerGetIPPort(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", }, }, @@ -3642,16 +3641,16 @@ func TestDockerGetIPPort(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", }, }, @@ -3702,16 +3701,16 @@ func TestDockerGetPort(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", }, @@ -3724,17 +3723,17 @@ func TestDockerGetPort(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", @@ -3886,7 +3885,7 @@ func TestSwarmGetIPAddress(t *testing.T) { expected: "10.11.12.13", networks: map[string]*networktypes.Summary{ "1": { - Name: "foo", + Network: networktypes.Network{Name: "foo"}, }, }, }, @@ -3904,10 +3903,10 @@ func TestSwarmGetIPAddress(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"}, }, }, }, diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go index 194251107..844a4e396 100644 --- a/pkg/provider/docker/docker.go +++ b/pkg/provider/docker/docker.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "net" "net/http" "strconv" "strings" @@ -14,15 +13,13 @@ import ( "github.com/cenkalti/backoff/v4" "github.com/docker/cli/cli/connhelper" - dockercontainertypes "github.com/docker/docker/api/types/container" - eventtypes "github.com/docker/docker/api/types/events" - "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" - "github.com/docker/go-connections/nat" "github.com/docker/go-connections/sockets" + dockercontainertypes "github.com/moby/moby/api/types/container" + eventtypes "github.com/moby/moby/api/types/events" + 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" ptypes "github.com/traefik/paerser/types" "github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/job" @@ -91,7 +88,7 @@ type dockerData struct { // NetworkSettings holds the networks data to the provider. type networkSettings struct { NetworkMode dockercontainertypes.NetworkMode - Ports nat.PortMap + Ports networktypes.PortMap Networks map[string]*networkData } @@ -124,7 +121,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe. } defer dockerClient.Close() - serverVersion, err := dockerClient.ServerVersion(ctx) + serverVersion, err := dockerClient.ServerVersion(ctx, client.ServerVersionOptions{}) if err != nil { logger.Errorf("Failed to retrieve information of the docker client and server host: %s", err) return err @@ -191,12 +188,6 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe. } // channel closed } else { - f := filters.NewArgs() - f.Add("type", "container") - options := eventtypes.ListOptions{ - Filters: f, - } - startStopHandle := func(m eventtypes.Message) { logger.Debugf("Provider event received %+v", m) containers, err := p.listContainers(ctx, dockerClient) @@ -219,16 +210,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("Provider event stream closed") } @@ -265,10 +258,9 @@ func (p *Provider) createClient() (client.APIClient, error) { } opts = append(opts, client.FromEnv, - client.WithAPIVersionNegotiation(), client.WithHTTPHeaders(httpHeaders)) - return client.NewClientWithOpts(opts...) + return client.New(opts...) } func (p *Provider) getClientOpts() ([]client.Opt, error) { @@ -328,14 +320,14 @@ func (p *Provider) getClientOpts() ([]client.Opt, error) { } func (p *Provider) listContainers(ctx context.Context, dockerClient client.ContainerAPIClient) ([]dockerData, error) { - containerList, err := dockerClient.ContainerList(ctx, dockercontainertypes.ListOptions{}) + containerList, err := dockerClient.ContainerList(ctx, client.ContainerListOptions{}) if err != nil { return nil, err } var inspectedContainers []dockerData // get inspect containers - for _, container := range containerList { + for _, container := range containerList.Items { dData := inspectContainers(ctx, dockerClient, container.ID) if len(dData.Name) == 0 { continue @@ -354,7 +346,7 @@ func (p *Provider) listContainers(ctx context.Context, dockerClient client.Conta } 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 { log.FromContext(ctx).Warnf("Failed to inspect container %s, error: %s", containerID, err) return dockerData{} @@ -362,8 +354,8 @@ func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClie // This condition is here to avoid to have empty IP https://github.com/traefik/traefik/issues/2459 // We register only container which are running - if containerInspected.ContainerJSONBase != nil && containerInspected.ContainerJSONBase.State != nil && containerInspected.ContainerJSONBase.State.Running { - return parseContainer(containerInspected) + if res.Container.State != nil && res.Container.State.Running { + return parseContainer(res.Container) } return dockerData{} @@ -371,21 +363,18 @@ func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClie func parseContainer(container dockercontainertypes.InspectResponse) dockerData { dData := dockerData{ + ID: container.ID, + Name: container.Name, + ServiceName: container.Name, // Default ServiceName to be the container's Name. 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. + 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 = string(container.State.Health.Status) } if container.Config != nil && container.Config.Labels != nil { @@ -399,9 +388,11 @@ func parseContainer(container dockercontainertypes.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{ @@ -418,17 +409,17 @@ func parseContainer(container dockercontainertypes.InspectResponse) dockerData { func (p *Provider) listServices(ctx context.Context, dockerClient client.APIClient) ([]dockerData, error) { logger := log.FromContext(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") @@ -436,21 +427,21 @@ func (p *Provider) listServices(ctx context.Context, dockerClient client.APIClie 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.Debugf("Failed to network inspect on client for docker, error: %s", err) 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.Errorf("Skip container %s: %v", getServiceName(dData), err) @@ -501,21 +492,20 @@ func (p *Provider) parseService(ctx context.Context, service swarmtypes.Service, dData.NetworkSettings.Networks = make(map[string]*networkData) for _, virtualIP := range service.Endpoint.VirtualIPs { networkService := networkMap[virtualIP.NetworkID] - if networkService != nil { - if len(virtualIP.Addr) > 0 { - ip, _, _ := net.ParseCIDR(virtualIP.Addr) - network := &networkData{ - Name: networkService.Name, - ID: virtualIP.NetworkID, - Addr: ip.String(), - } - dData.NetworkSettings.Networks[network.Name] = network - } else { - logger.Debugf("No virtual IPs found in network %s", virtualIP.NetworkID) - } - } else { + if networkService == nil { logger.Debugf("Network not found, id: %s", virtualIP.NetworkID) + continue } + if !virtualIP.Addr.Addr().IsValid() { + logger.Debugf("No virtual IPs found in network %s", virtualIP.NetworkID) + continue + } + network := &networkData{ + Name: networkService.Name, + ID: virtualIP.NetworkID, + Addr: virtualIP.Addr.Addr().String(), + } + dData.NetworkSettings.Networks[network.Name] = network } } } @@ -525,17 +515,15 @@ func (p *Provider) parseService(ctx context.Context, service swarmtypes.Service, 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 } @@ -570,11 +558,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 { @@ -584,11 +572,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 } diff --git a/pkg/provider/docker/swarm_test.go b/pkg/provider/docker/swarm_test.go index 1136b249f..5dcda99f6 100644 --- a/pkg/provider/docker/swarm_test.go +++ b/pkg/provider/docker/swarm_test.go @@ -6,29 +6,28 @@ import ( "testing" "time" - dockertypes "github.com/docker/docker/api/types" - dockercontainertypes "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" + dockercontainertypes "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type fakeTasksClient struct { - dockerclient.APIClient + client.APIClient tasks []swarmtypes.Task container dockercontainertypes.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) (dockercontainertypes.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 } func TestListTasks(t *testing.T) { @@ -74,7 +73,7 @@ func TestListTasks(t *testing.T) { }, networks: map[string]*networktypes.Summary{ "1": { - Name: "foo", + Network: networktypes.Network{Name: "foo"}, }, }, }, @@ -105,7 +104,7 @@ func TestListTasks(t *testing.T) { } type fakeServicesClient struct { - dockerclient.APIClient + client.APIClient dockerVersion string networks []networktypes.Summary @@ -115,29 +114,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 } func TestListServices(t *testing.T) { @@ -200,21 +199,23 @@ func TestListServices(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", + }, }, }, }, @@ -255,21 +256,23 @@ func TestListServices(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", + }, }, }, }, @@ -334,7 +337,7 @@ func TestSwarmTaskParsing(t *testing.T) { }, networks: map[string]*networktypes.Summary{ "1": { - Name: "foo", + Network: networktypes.Network{Name: "foo"}, }, }, }, @@ -359,7 +362,7 @@ func TestSwarmTaskParsing(t *testing.T) { }, networks: map[string]*networktypes.Summary{ "1": { - Name: "foo", + Network: networktypes.Network{Name: "foo"}, }, }, }, @@ -397,7 +400,7 @@ func TestSwarmTaskParsing(t *testing.T) { }, networks: map[string]*networktypes.Summary{ "1": { - Name: "vlan", + Network: networktypes.Network{Name: "vlan"}, }, }, }, @@ -425,7 +428,7 @@ func TestSwarmTaskParsing(t *testing.T) { }, networks: map[string]*networktypes.Summary{ "1": { - Name: "foo", + Network: networktypes.Network{Name: "foo"}, }, }, }, diff --git a/pkg/provider/ecs/config.go b/pkg/provider/ecs/config.go index 94898575b..58b6d2090 100644 --- a/pkg/provider/ecs/config.go +++ b/pkg/provider/ecs/config.go @@ -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/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/config/label" "github.com/traefik/traefik/v2/pkg/log" @@ -302,26 +305,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 { From ee94dc5343d7c58a02932d055073a936567ffdc1 Mon Sep 17 00:00:00 2001 From: Kevin Pollet Date: Tue, 5 May 2026 14:22:05 +0200 Subject: [PATCH 4/4] Prepare release v2.11.45 --- CHANGELOG.md | 7 +++++++ script/gcg/traefik-bugfix.toml | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbb2e3e91..bf7bf402d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [v2.11.45](https://github.com/traefik/traefik/tree/v2.11.45) (2026-05-05) +[All Commits](https://github.com/traefik/traefik/compare/v2.11.44...v2.11.45) + +**Bug fixes:** +- **[k8s/crd]** Remove cross-provider sanitization for Kubernetes service loading ([#13087](https://github.com/traefik/traefik/pull/13087) @rtribotte) +- **[docker, ecs]** Migrate to github.com/moby/moby modules ([#13053](https://github.com/traefik/traefik/pull/13053) @mmatur) + ## [v2.11.44](https://github.com/traefik/traefik/tree/v2.11.44) (2026-04-29) [All Commits](https://github.com/traefik/traefik/compare/v2.11.43...v2.11.44) diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index f40819ed1..668b9706e 100644 --- a/script/gcg/traefik-bugfix.toml +++ b/script/gcg/traefik-bugfix.toml @@ -4,11 +4,11 @@ RepositoryName = "traefik" OutputType = "file" FileName = "traefik_changelog.md" -# example new bugfix v2.11.44 +# example new bugfix v2.11.45 CurrentRef = "v2.11" -PreviousRef = "v2.11.43" +PreviousRef = "v2.11.44" BaseBranch = "v2.11" -FutureCurrentRefName = "v2.11.44" +FutureCurrentRefName = "v2.11.45" ThresholdPreviousRef = 10000 ThresholdCurrentRef = 10000