From 2982e26ddab36a85c52740418c12140a7ee723e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Mon, 11 Mar 2024 10:12:55 +0800 Subject: [PATCH] add fault plugin (#368) Signed-off-by: spacewander --- controller/Dockerfile | 1 + .../translation/testdata/plugins/fault.in.yml | 18 +++++ .../testdata/plugins/fault.out.yml | 47 +++++++++++++ controller/plugins/fault/config.go | 61 ++++++++++++++++ controller/plugins/plugins.go | 1 + e2e/tests/fault.go | 34 +++++++++ e2e/tests/fault.yml | 16 +++++ .../en/docs/reference/plugins/fault.md | 69 +++++++++++++++++++ .../zh-hans/docs/reference/plugins/fault.md | 69 +++++++++++++++++++ 9 files changed, 316 insertions(+) create mode 100644 controller/internal/translation/testdata/plugins/fault.in.yml create mode 100644 controller/internal/translation/testdata/plugins/fault.out.yml create mode 100644 controller/plugins/fault/config.go create mode 100644 e2e/tests/fault.go create mode 100644 e2e/tests/fault.yml create mode 100644 site/content/en/docs/reference/plugins/fault.md create mode 100644 site/content/zh-hans/docs/reference/plugins/fault.md diff --git a/controller/Dockerfile b/controller/Dockerfile index 05b9df50..decdd798 100644 --- a/controller/Dockerfile +++ b/controller/Dockerfile @@ -32,6 +32,7 @@ COPY go.mod go.sum ./ RUN go mod download # TODO: find a way to cache controller dependencies COPY api/ api/ +COPY internal/ internal/ COPY pkg/ pkg/ COPY plugins/ plugins/ COPY controller/ controller/ diff --git a/controller/internal/translation/testdata/plugins/fault.in.yml b/controller/internal/translation/testdata/plugins/fault.in.yml new file mode 100644 index 00000000..dab72395 --- /dev/null +++ b/controller/internal/translation/testdata/plugins/fault.in.yml @@ -0,0 +1,18 @@ +apiVersion: mosn.io/v1 +kind: HTTPFilterPolicy +metadata: + name: policy + namespace: default +spec: + targetRef: + group: networking.istio.io + kind: VirtualService + name: default + filters: + fault: + config: + maxActiveFaults: 100 + abort: + headerAbort: {} + percentage: + numerator: 100 diff --git a/controller/internal/translation/testdata/plugins/fault.out.yml b/controller/internal/translation/testdata/plugins/fault.out.yml new file mode 100644 index 00000000..b32f8c2c --- /dev/null +++ b/controller/internal/translation/testdata/plugins/fault.out.yml @@ -0,0 +1,47 @@ +- metadata: + creationTimestamp: null + name: htnn-h-default.local + spec: + configPatches: + - applyTo: HTTP_ROUTE + match: + routeConfiguration: + vhost: + name: default.local:80 + route: + name: default/default + patch: + operation: MERGE + value: + typed_per_filter_config: + htnn.filters.http.fault: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + abort: + headerAbort: {} + percentage: + numerator: 100 + maxActiveFaults: 100 + status: {} +- metadata: + creationTimestamp: null + name: htnn-http-filter + spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: GATEWAY + listener: + filterChain: + filter: + name: envoy.filters.network.http_connection_manager + subFilter: + name: htnn.filters.http.golang + patch: + operation: INSERT_BEFORE + value: + disabled: true + name: htnn.filters.http.fault + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + priority: 100 + status: {} diff --git a/controller/plugins/fault/config.go b/controller/plugins/fault/config.go new file mode 100644 index 00000000..d7a78d46 --- /dev/null +++ b/controller/plugins/fault/config.go @@ -0,0 +1,61 @@ +// Copyright The HTNN Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fault + +import ( + fault "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/fault/v3" + + "mosn.io/htnn/pkg/filtermanager/api" + "mosn.io/htnn/pkg/plugins" +) + +const ( + Name = "fault" +) + +func init() { + plugins.RegisterHttpPlugin(Name, &plugin{}) +} + +type plugin struct { + plugins.PluginMethodDefaultImpl +} + +func (p *plugin) Type() plugins.PluginType { + return plugins.TypeGeneral +} + +func (p *plugin) Order() plugins.PluginOrder { + return plugins.PluginOrder{ + Position: plugins.OrderPositionOuter, + Operation: plugins.OrderOperationInsertLast, + } +} + +func (p *plugin) Config() api.PluginConfig { + return &fault.HTTPFault{} +} + +func (p *plugin) RouteConfigTypeURL() string { + return "type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault" +} + +func (p *plugin) HTTPFilterConfigPlaceholder() map[string]interface{} { + return map[string]interface{}{ + "typed_config": map[string]interface{}{ + "@type": p.RouteConfigTypeURL(), + }, + } +} diff --git a/controller/plugins/plugins.go b/controller/plugins/plugins.go index 5ac025cf..fa97f31a 100644 --- a/controller/plugins/plugins.go +++ b/controller/plugins/plugins.go @@ -17,6 +17,7 @@ package plugins import ( _ "mosn.io/htnn/controller/plugins/bandwidth_limit" _ "mosn.io/htnn/controller/plugins/buffer" + _ "mosn.io/htnn/controller/plugins/fault" _ "mosn.io/htnn/controller/plugins/local_ratelimit" _ "mosn.io/htnn/controller/plugins/lua" _ "mosn.io/htnn/plugins" // register Go plugins diff --git a/e2e/tests/fault.go b/e2e/tests/fault.go new file mode 100644 index 00000000..ecde8677 --- /dev/null +++ b/e2e/tests/fault.go @@ -0,0 +1,34 @@ +// Copyright The HTNN Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tests + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "mosn.io/htnn/e2e/pkg/suite" +) + +func init() { + suite.Register(suite.Test{ + Manifests: []string{"base/httproute.yml"}, + Run: func(t *testing.T, suite *suite.Suite) { + resp, err := suite.Head("/echo", nil) + require.NoError(t, err) + require.Equal(t, 401, resp.StatusCode) + }, + }) +} diff --git a/e2e/tests/fault.yml b/e2e/tests/fault.yml new file mode 100644 index 00000000..e1178d06 --- /dev/null +++ b/e2e/tests/fault.yml @@ -0,0 +1,16 @@ +apiVersion: mosn.io/v1 +kind: HTTPFilterPolicy +metadata: + name: policy +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: default + filters: + fault: + config: + abort: + http_status: 401 + percentage: + numerator: 100 diff --git a/site/content/en/docs/reference/plugins/fault.md b/site/content/en/docs/reference/plugins/fault.md new file mode 100644 index 00000000..fa2f8893 --- /dev/null +++ b/site/content/en/docs/reference/plugins/fault.md @@ -0,0 +1,69 @@ +--- +title: Fault +--- + +## Description + +The `fault` plugin supports response and delay injections by leveraging Envoy's `fault` filter. + +## Attribute + +| | | +|-------|---------| +| Type | General | +| Order | Outer | + +## Configuration + +See the corresponding [Envoy documentation](https://www.envoyproxy.io/docs/envoy/v1.28.0/configuration/http/http_filters/fault_filter). + +## Usage + +Assumed we have the HTTPRoute below attached to `localhost:10000`, and a backend server listening to port `8080`: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: default +spec: + parentRefs: + - name: default + namespace: default + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: backend + port: 8080 +``` + +By applying the configuration below, requests sent to `http://localhost:10000/` will receive a 401 response 100% of the time: + +```yaml +apiVersion: mosn.io/v1 +kind: HTTPFilterPolicy +metadata: + name: policy +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: default + filters: + fault: + config: + abort: + http_status: 401 + percentage: + numerator: 100 +``` + +Let's try it out: + +``` +$ curl http://localhost:10000/ -i 2>/dev/null | head -1 +HTTP/1.1 401 Unauthorized +``` diff --git a/site/content/zh-hans/docs/reference/plugins/fault.md b/site/content/zh-hans/docs/reference/plugins/fault.md new file mode 100644 index 00000000..17346288 --- /dev/null +++ b/site/content/zh-hans/docs/reference/plugins/fault.md @@ -0,0 +1,69 @@ +--- +title: Fault +--- + +## 说明 + +`fault` 插件支持通过利用 Envoy 的 `fault` 过滤器注入响应和延迟。 + +## 属性 + +| | | +|-------|---------| +| Type | General | +| Order | Outer | + +## 配置 + +请参阅相应的 [Envoy 文档](https://www.envoyproxy.io/docs/envoy/v1.28.0/configuration/http/http_filters/fault_filter)。 + +## 用法 + +假设我们有下面附加到 `localhost:10000` 的 HTTPRoute,并且有一个后端服务器监听端口 `8080`: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: default +spec: + parentRefs: + - name: default + namespace: default + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: backend + port: 8080 +``` + +通过应用下面的配置,发送到 `http://localhost:10000/` 的请求将 100% 收到 401 响应: + +```yaml +apiVersion: mosn.io/v1 +kind: HTTPFilterPolicy +metadata: + name: policy +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: default + filters: + fault: + config: + abort: + http_status: 401 + percentage: + numerator: 100 +``` + +让我们试一下: + +``` +$ curl http://localhost:10000/ -i 2>/dev/null | head -1 +HTTP/1.1 401 Unauthorized +```