From c5808af4d9db891789ba883015c7824ff923d88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Ch=C3=A1vez?= Date: Tue, 27 Feb 2024 14:22:04 +0100 Subject: [PATCH 1/3] chore: upgrades http-wasm host to v0.6.0 to support clients using v0.4.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 247f2cd25..690101445 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.5 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/nomad/api v0.0.0-20240122103822-8a4bd61caf74 - github.com/http-wasm/http-wasm-host-go v0.5.2 + github.com/http-wasm/http-wasm-host-go v0.6.0 github.com/influxdata/influxdb-client-go/v2 v2.7.0 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d github.com/klauspost/compress v1.17.2 diff --git a/go.sum b/go.sum index 463c81da4..8bcf31516 100644 --- a/go.sum +++ b/go.sum @@ -598,8 +598,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/http-wasm/http-wasm-host-go v0.5.2 h1:5d/QgaaJtTF+qd0goBaxJJ7tcHP9n+gQUldJ7TsTexA= -github.com/http-wasm/http-wasm-host-go v0.5.2/go.mod h1:zQB3w+df4hryDEqBorGyA1DwPJ86LfKIASNLFuj6CuI= +github.com/http-wasm/http-wasm-host-go v0.6.0 h1:Vd4XvcFB3NMgWp2VLCQaiqYgLneN2lChbyN9NGoNDro= +github.com/http-wasm/http-wasm-host-go v0.6.0/go.mod h1:zQB3w+df4hryDEqBorGyA1DwPJ86LfKIASNLFuj6CuI= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= From 0e89a6bec76dc2e05cff334790b7385bf1e94dc7 Mon Sep 17 00:00:00 2001 From: DJ Enriquez Date: Tue, 27 Feb 2024 12:30:04 -0800 Subject: [PATCH 2/3] ConsulCatalog StrictChecks --- docs/content/providers/consul-catalog.md | 26 + .../reference/static-configuration/cli-ref.md | 3 + .../reference/static-configuration/env-ref.md | 3 + .../reference/static-configuration/file.toml | 1 + .../reference/static-configuration/file.yaml | 3 + pkg/provider/consulcatalog/config.go | 9 +- pkg/provider/consulcatalog/config_test.go | 470 +++++++++++++++++- pkg/provider/consulcatalog/consul_catalog.go | 18 + 8 files changed, 521 insertions(+), 12 deletions(-) diff --git a/docs/content/providers/consul-catalog.md b/docs/content/providers/consul-catalog.md index 3c601da31..cdec6ae86 100644 --- a/docs/content/providers/consul-catalog.md +++ b/docs/content/providers/consul-catalog.md @@ -714,6 +714,32 @@ providers: # ... ``` +### `strictChecks` + +_Optional, Default="passing,warning"_ + +Define which [Consul Service health checks](https://developer.hashicorp.com/consul/docs/services/usage/checks#define-initial-health-check-status) are allowed to take on traffic. + +```yaml tab="File (YAML)" +providers: + consulCatalog: + strictChecks: + - "passing" + - "warning" + # ... +``` + +```toml tab="File (TOML)" +[providers.consulCatalog] + strictChecks = ["passing", "warning"] + # ... +``` + +```bash tab="CLI" +--providers.consulcatalog.strictChecks=passing,warning +# ... +``` + ### `watch` _Optional, Default=false_ diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index 179e376c5..d78150a72 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -537,6 +537,9 @@ Name of the Traefik service in Consul Catalog (needs to be registered via the or `--providers.consulcatalog.stale`: Use stale consistency for catalog reads. (Default: ```false```) +`--providers.consulcatalog.strictchecks`: +A list of service health statuses to allow taking traffic. (Default: ```passing, warning```) + `--providers.consulcatalog.watch`: Watch Consul API events. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index e2a2e73f6..7947b9ddd 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -513,6 +513,9 @@ Name of the Traefik service in Consul Catalog (needs to be registered via the or `TRAEFIK_PROVIDERS_CONSULCATALOG_STALE`: Use stale consistency for catalog reads. (Default: ```false```) +`TRAEFIK_PROVIDERS_CONSULCATALOG_STRICTCHECKS`: +A list of service health statuses to allow taking traffic. (Default: ```passing, warning```) + `TRAEFIK_PROVIDERS_CONSULCATALOG_WATCH`: Watch Consul API events. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index e3de7aa3b..504d7c9b6 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -161,6 +161,7 @@ connectByDefault = true serviceName = "foobar" watch = true + strictChecks = ["foobar", "foobar"] namespaces = ["foobar", "foobar"] [providers.consulCatalog.endpoint] address = "foobar" diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index bdf314c29..ffb9d75d8 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -192,6 +192,9 @@ providers: connectByDefault: true serviceName: foobar watch: true + strictChecks: + - foobar + - foobar namespaces: - foobar - foobar diff --git a/pkg/provider/consulcatalog/config.go b/pkg/provider/consulcatalog/config.go index a45696fd4..98c320013 100644 --- a/pkg/provider/consulcatalog/config.go +++ b/pkg/provider/consulcatalog/config.go @@ -132,8 +132,8 @@ func (p *Provider) keepContainer(ctx context.Context, item itemData) bool { return false } - if item.Status != api.HealthPassing && item.Status != api.HealthWarning { - logger.Debug().Msg("Filtering unhealthy or starting item") + if !p.includesHealthStatus(item.Status) { + logger.Debug().Msgf("Status %q is not included in the configured strictChecks of %q", item.Status, strings.Join(p.StrictChecks, ",")) return false } @@ -324,3 +324,8 @@ func getName(i itemData) string { hasher.Write([]byte(strings.Join(tags, ""))) return provider.Normalize(fmt.Sprintf("%s-%d", i.Name, hasher.Sum64())) } + +// defaultStrictChecks returns the default healthchecks to allow an upstream to be registered a route for loadbalancers. +func defaultStrictChecks() []string { + return []string{api.HealthPassing, api.HealthWarning} +} diff --git a/pkg/provider/consulcatalog/config_test.go b/pkg/provider/consulcatalog/config_test.go index 5370a75ca..4649eb3bd 100644 --- a/pkg/provider/consulcatalog/config_test.go +++ b/pkg/provider/consulcatalog/config_test.go @@ -287,11 +287,13 @@ func TestDefaultRule(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() + var config Configuration + + config.SetDefaults() + config.DefaultRule = test.defaultRule + p := Provider{ - Configuration: Configuration{ - ExposedByDefault: true, - DefaultRule: test.defaultRule, - }, + Configuration: config, } err := p.Init() @@ -3125,13 +3127,15 @@ func Test_buildConfiguration(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() + var config Configuration + + config.SetDefaults() + config.DefaultRule = "Host(`{{ normalize .Name }}.traefik.wtf`)" + config.ConnectAware = test.ConnectAware + config.Constraints = test.constraints + p := Provider{ - Configuration: Configuration{ - ExposedByDefault: true, - DefaultRule: "Host(`{{ normalize .Name }}.traefik.wtf`)", - ConnectAware: test.ConnectAware, - Constraints: test.constraints, - }, + Configuration: config, } err := p.Init() @@ -3206,3 +3210,449 @@ func extractNSFromProvider(providers []*Provider) []string { } return res } + +func TestFilterHealthStatuses(t *testing.T) { + testCases := []struct { + desc string + items []itemData + strictChecks []string + expected *dynamic.Configuration + }{ + { + // No value passed in here, we assume the default of ["passing", "warning"] + desc: "test default strict checks", + strictChecks: defaultStrictChecks(), + items: []itemData{ + { + ID: "id", + Node: "Node1", + Name: "Test1", + Address: "127.0.0.1", + Port: "80", + Labels: nil, + Status: api.HealthPassing, + }, + { + ID: "id", + Node: "Node2", + Name: "Test2", + Address: "127.0.0.1", + Port: "81", + Labels: nil, + Status: api.HealthWarning, + }, + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + ServersTransports: map[string]*dynamic.TCPServersTransport{}, + }, + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{}, + Services: map[string]*dynamic.UDPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "Test1": { + Service: "Test1", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + "Test2": { + Service: "Test2", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + }, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{ + "Test1": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:80", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + "Test2": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:81", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + }, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, + { + // The item's health status is not included in the default checks, do not expect any containers + desc: "test status not included", + strictChecks: defaultStrictChecks(), + items: []itemData{ + { + ID: "id", + Node: "Node1", + Name: "Test", + Address: "127.0.0.1", + Port: "80", + Labels: nil, + Status: api.HealthCritical, + }, + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + ServersTransports: map[string]*dynamic.TCPServersTransport{}, + }, + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{}, + Services: map[string]*dynamic.UDPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{}, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{}, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, + { + // Allow only "warning" status containers to be included + desc: "test only include warning", + strictChecks: []string{api.HealthWarning}, + items: []itemData{ + { + ID: "id", + Node: "Node1", + Name: "Test1", + Address: "127.0.0.1", + Port: "80", + Labels: nil, + Status: api.HealthPassing, + }, + { + ID: "id2", + Node: "Node2", + Name: "Test2", + Address: "127.0.0.1", + Port: "81", + Labels: nil, + Status: api.HealthWarning, + }, + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + ServersTransports: map[string]*dynamic.TCPServersTransport{}, + }, + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{}, + Services: map[string]*dynamic.UDPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "Test2": { + Service: "Test2", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + }, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{ + "Test2": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:81", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + }, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, + { + // Reject "critical" health status + desc: "test critical status not included", + strictChecks: defaultStrictChecks(), + items: []itemData{ + { + ID: "id", + Node: "Node1", + Name: "Test1", + Address: "127.0.0.1", + Port: "80", + Labels: nil, + Status: api.HealthPassing, + }, + { + ID: "id2", + Node: "Node2", + Name: "Test2", + Address: "127.0.0.1", + Port: "81", + Labels: nil, + Status: api.HealthWarning, + }, + { + ID: "id3", + Node: "Node3", + Name: "Test3", + Address: "127.0.0.1", + Port: "82", + Labels: nil, + Status: api.HealthCritical, + }, + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + ServersTransports: map[string]*dynamic.TCPServersTransport{}, + }, + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{}, + Services: map[string]*dynamic.UDPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "Test1": { + Service: "Test1", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + "Test2": { + Service: "Test2", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + }, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{ + "Test1": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:80", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + "Test2": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:81", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + }, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, + { + // The "any" health status allows for all status types, including ones not yet directly included in Consul + desc: "test include 'any' health status", + strictChecks: []string{api.HealthAny}, + items: []itemData{ + { + ID: "id", + Node: "Node1", + Name: "Test1", + Address: "127.0.0.1", + Port: "80", + Labels: nil, + Status: api.HealthPassing, + }, + { + ID: "id2", + Node: "Node2", + Name: "Test2", + Address: "127.0.0.1", + Port: "81", + Labels: nil, + Status: api.HealthWarning, + }, + { + ID: "id3", + Node: "Node3", + Name: "Test3", + Address: "127.0.0.1", + Port: "82", + Labels: nil, + Status: api.HealthCritical, + }, + { + ID: "id4", + Node: "Node4", + Name: "Test4", + Address: "127.0.0.1", + Port: "83", + Labels: nil, + Status: "some unsupported status", + }, + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + ServersTransports: map[string]*dynamic.TCPServersTransport{}, + }, + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{}, + Services: map[string]*dynamic.UDPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "Test1": { + Service: "Test1", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + "Test2": { + Service: "Test2", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + "Test3": { + Service: "Test3", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + "Test4": { + Service: "Test4", + Rule: "Host(`foo.bar`)", + DefaultRule: true, + }, + }, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{ + "Test1": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:80", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + "Test2": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:81", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + "Test3": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:82", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + "Test4": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:83", + }, + }, + PassHostHeader: Bool(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: ptypes.Duration(100 * time.Millisecond), + }, + }, + }, + }, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + var config Configuration + + config.SetDefaults() + config.DefaultRule = "Host(`foo.bar`)" + + if test.strictChecks != nil { + config.StrictChecks = test.strictChecks + } + + p := Provider{ + Configuration: config, + } + + err := p.Init() + require.NoError(t, err) + + for i := 0; i < len(test.items); i++ { + var err error + test.items[i].ExtraConf, err = p.getExtraConf(test.items[i].Labels) + require.NoError(t, err) + } + + configuration := p.buildConfiguration(context.Background(), test.items, nil) + + assert.Equal(t, test.expected, configuration) + }) + } +} diff --git a/pkg/provider/consulcatalog/consul_catalog.go b/pkg/provider/consulcatalog/consul_catalog.go index 696214e0c..55c24edb6 100644 --- a/pkg/provider/consulcatalog/consul_catalog.go +++ b/pkg/provider/consulcatalog/consul_catalog.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strconv" + "strings" "text/template" "time" @@ -88,6 +89,7 @@ type Configuration struct { ConnectByDefault bool `description:"Consider every service as Connect capable by default." json:"connectByDefault,omitempty" toml:"connectByDefault,omitempty" yaml:"connectByDefault,omitempty" export:"true"` ServiceName string `description:"Name of the Traefik service in Consul Catalog (needs to be registered via the orchestrator or manually)." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"` Watch bool `description:"Watch Consul API events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"` + StrictChecks []string `description:"A list of service health statuses to allow taking traffic." json:"strictChecks,omitempty" toml:"strictChecks,omitempty" yaml:"strictChecks,omitempty" export:"true"` } // SetDefaults sets the default values. @@ -98,6 +100,7 @@ func (c *Configuration) SetDefaults() { c.ExposedByDefault = true c.DefaultRule = defaultTemplateRule c.ServiceName = "traefik" + c.StrictChecks = defaultStrictChecks() } // Provider is the Consul Catalog provider implementation. @@ -578,6 +581,21 @@ func (p *Provider) watchConnectTLS(ctx context.Context) error { } } +// includesHealthStatus returns true if the status passed in exists in the configured StrictChecks configuration. Statuses are case insensitive. +func (p *Provider) includesHealthStatus(status string) bool { + for _, s := range p.StrictChecks { + // If the "any" status is included, assume all health checks are included + if strings.EqualFold(s, api.HealthAny) { + return true + } + + if strings.EqualFold(s, status) { + return true + } + } + return false +} + func createClient(namespace string, endpoint *EndpointConfig) (*api.Client, error) { config := api.Config{ Address: endpoint.Address, From 86be0a4e6f0f7250c19e4ee56b73282bc9ae8466 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:18:05 +0100 Subject: [PATCH 3/3] fix: invalid version in docs about Gateway API on Traefik v3 --- docs/content/providers/kubernetes-gateway.md | 2 +- docs/content/routing/providers/kubernetes-gateway.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/content/providers/kubernetes-gateway.md b/docs/content/providers/kubernetes-gateway.md index e23fef820..95b5ffd02 100644 --- a/docs/content/providers/kubernetes-gateway.md +++ b/docs/content/providers/kubernetes-gateway.md @@ -14,7 +14,7 @@ The Gateway API project is part of Kubernetes, working under SIG-NETWORK. The Kubernetes Gateway provider is a Traefik implementation of the [Gateway API](https://gateway-api.sigs.k8s.io/) specifications from the Kubernetes Special Interest Groups (SIGs). -This provider is proposed as an experimental feature and partially supports the Gateway API [v0.4.0](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v0.4.0) specification. +This provider is proposed as an experimental feature and partially supports Gateway API [v1.0.0](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.0.0) specification. !!! warning "Enabling The Experimental Kubernetes Gateway Provider" diff --git a/docs/content/routing/providers/kubernetes-gateway.md b/docs/content/routing/providers/kubernetes-gateway.md index e8d11c426..dc024f86f 100644 --- a/docs/content/routing/providers/kubernetes-gateway.md +++ b/docs/content/routing/providers/kubernetes-gateway.md @@ -5,7 +5,8 @@ description: "The Kubernetes Gateway API can be used as a provider for routing a # Traefik & Kubernetes -The Kubernetes Gateway API, The Experimental Way. {: .subtitle } +The Kubernetes Gateway API, The Experimental Way. +{: .subtitle } ## Configuration Examples