This is an automated email from the ASF dual-hosted git repository.
mark4z pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go-pixiu.git
The following commit(s) were added to refs/heads/develop by this push:
new 16be85ff feat(failinject): add failinject feature (#571)
16be85ff is described below
commit 16be85ff6c630ec821b01f170b2cb9d50319e239
Author: marlon <[email protected]>
AuthorDate: Sun Sep 24 14:52:20 2023 +0800
feat(failinject): add failinject feature (#571)
* feat(failinject): add failinject feature
* fix: fix response body error
* chore: change document for failinject config
* chore: remove debug info and add comment
* failinject's Delay do not break request
---------
Co-authored-by: Mark4z <[email protected]>
---
docs/sample/others/fail-inject.md | 68 +++++++++++++++
pixiu/pkg/common/constant/key.go | 1 +
pixiu/pkg/filter/failinject/config.go | 45 ++++++++++
pixiu/pkg/filter/failinject/filter.go | 151 ++++++++++++++++++++++++++++++++++
pixiu/pkg/pluginregistry/registry.go | 1 +
5 files changed, 266 insertions(+)
diff --git a/docs/sample/others/fail-inject.md
b/docs/sample/others/fail-inject.md
new file mode 100644
index 00000000..226f8d02
--- /dev/null
+++ b/docs/sample/others/fail-inject.md
@@ -0,0 +1,68 @@
+# Fail Inject Filter Quick Start
+
+## Start Pixiu:
+
+Examples of official references is in
`https://github.com/dubbo-go-pixiu/samples`
+
+Add the following configuration file to the
`samples/http/simple/pixiu/conf.yaml`
+
+```yaml
+static_resources:
+ listeners:
+ - name: "net/http"
+ protocol_type: "HTTP"
+ address:
+ socket_address:
+ address: "0.0.0.0"
+ port: 8888
+ filter_chains:
+ filters:
+ - name: dgp.filter.httpconnectionmanager
+ config:
+ route_config:
+ routes:
+ - match:
+ prefix: /user
+ route:
+ cluster: user
+ cluster_not_found_response_code: 505
+ http_filters:
+ - name: dgp.filter.http.faultinjection
+ config:
+ fail_inject_rules:
+
"/UserService/com.dubbogo.pixiu.UserService/GetUserByCode":
+ type: delay
+ trigger_type: random
+ status_code: 500
+ body: 'error'
+ delay: 5s
+ odds: 30
+ config:
+ idle_timeout: 5s
+ read_timeout: 5s
+ write_timeout: 5s
+ clusters:
+ - name: "user"
+ lb_policy: "lb"
+ endpoints:
+ - id: 1
+ socket_address:
+ address: 127.0.0.1
+ port: 1314
+ health_checks:
+ - protocol: "tcp"
+ timeout: 1s
+ interval: 2s
+ healthy_threshold: 4
+ unhealthy_threshold: 4
+ shutdown_config:
+ timeout: "60s"
+ step_timeout: "10s"
+ reject_policy: "immediacy"
+```
+
+Then execute the following command .
+
+```shell
+go run cmd/pixiu/*.go gateway start -c samples/http/simplep/pixiu/conf.yaml
+```
diff --git a/pixiu/pkg/common/constant/key.go b/pixiu/pkg/common/constant/key.go
index 8c18336b..236415ca 100644
--- a/pixiu/pkg/common/constant/key.go
+++ b/pixiu/pkg/common/constant/key.go
@@ -47,6 +47,7 @@ const (
HTTPEventFilter = "dgp.filter.http.event"
HTTPTrafficFilter = "dgp.filter.http.traffic"
HTTPPrometheusMetricFilter = "dgp.filter.http.prometheusmetric"
+ HTTPFailInjectFilter = "dgp.filter.http.faultinjection"
DubboHttpFilter = "dgp.filter.dubbo.http"
DubboProxyFilter = "dgp.filter.dubbo.proxy"
diff --git a/pixiu/pkg/filter/failinject/config.go
b/pixiu/pkg/filter/failinject/config.go
new file mode 100644
index 00000000..d6952fa8
--- /dev/null
+++ b/pixiu/pkg/filter/failinject/config.go
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 failinject
+
+import "time"
+
+type URI string
+
+const (
+ TypeAbort = "abort"
+ TypeDelay = "delay"
+
+ TriggerTypeRandom = "random"
+ TriggerTypeAlways = "always"
+ TriggerTypePercentage = "percentage"
+)
+
+type (
+ Config struct {
+ Rules map[URI]*Rule `yaml:"fail_inject_rules"
json:"fail_inject_rules"`
+ }
+ Rule struct {
+ StatusCode int `yaml:"status_code"
json:"status_code"`
+ Body string `yaml:"body" json:"body"`
+ Type string `yaml:"type" json:"type"`
// abort, delay
+ TriggerType string `yaml:"trigger_type"
json:"trigger_type"` // random, always, percentage
+ Odds int `yaml:"odds" json:"odds"`
// 0-100
+ Delay time.Duration `yaml:"delay" json:"delay"`
+ }
+)
diff --git a/pixiu/pkg/filter/failinject/filter.go
b/pixiu/pkg/filter/failinject/filter.go
new file mode 100644
index 00000000..8a1dcc77
--- /dev/null
+++ b/pixiu/pkg/filter/failinject/filter.go
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 failinject
+
+import (
+ "math/rand"
+ "time"
+
+ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/common/constant"
+ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/common/extension/filter"
+ contextHttp "github.com/apache/dubbo-go-pixiu/pixiu/pkg/context/http"
+)
+
+const (
+ Kind = constant.HTTPFailInjectFilter
+)
+
+func init() {
+ filter.RegisterHttpFilter(&Plugin{})
+}
+
+type (
+ Plugin struct {
+ }
+
+ FilterFactory struct {
+ cfg *Config
+ }
+ Filter struct {
+ cfg *Config
+ }
+)
+
+func (factory *FilterFactory) Apply() error {
+ return nil
+}
+
+func (factory *FilterFactory) Config() interface{} {
+ return factory.cfg
+}
+
+func (factory *FilterFactory) PrepareFilterChain(ctx *contextHttp.HttpContext,
chain filter.FilterChain) error {
+ f := Filter{
+ cfg: factory.cfg,
+ }
+ chain.AppendDecodeFilters(f)
+ return nil
+}
+
+func (p *Plugin) Kind() string {
+ return Kind
+}
+
+func (p *Plugin) CreateFilterFactory() (filter.HttpFilterFactory, error) {
+ return &FilterFactory{
+ cfg: &Config{
+ Rules: make(map[URI]*Rule),
+ },
+ }, nil
+}
+
+func (f Filter) Decode(ctx *contextHttp.HttpContext) filter.FilterStatus {
+ uriCfg := &Rule{}
+ if v, ok := f.cfg.Rules[URI(ctx.Request.RequestURI)]; ok {
+ uriCfg = v
+ }
+ if uriCfg == nil {
+ return filter.Continue
+ }
+
+ matched := f.match(uriCfg)
+ if !matched {
+ return filter.Continue
+ }
+
+ if uriCfg.Type == TypeAbort {
+ ctx.SendLocalReply(uriCfg.StatusCode, []byte(uriCfg.Body))
+ return filter.Stop
+ }
+
+ if uriCfg.Type == TypeDelay {
+ time.Sleep(uriCfg.Delay)
+ return filter.Stop
+ }
+
+ return filter.Continue
+}
+
+// match determines whether a given request hits the error injection based on
the rule's trigger type.
+//
+// - If the rule is nil, the request doesn't hit the error injection.
+// - If the rule's trigger type is "Always", the request always hits the error
injection.
+// - If the rule's trigger type is "Percentage", the request hits the error
injection based on a specified percentage chance.
+// - If the rule's trigger type is "Random", the request hits the error
injection based on a random chance.
+//
+// Returns:
+// - true if the request hits the error injection
+// - false otherwise
+func (f Filter) match(rule *Rule) (matched bool) {
+ if rule == nil {
+ return false
+ }
+ if rule.TriggerType == TriggerTypeAlways {
+ return true
+ }
+ if rule.TriggerType == TriggerTypePercentage {
+ return percentage(rule.Odds)
+ }
+ if rule.TriggerType == TriggerTypeRandom {
+ return random()
+ }
+ return false
+}
+
+// random if the current request is matched
+func random() bool {
+ return (rand.Intn(1000)+1)%2 == 0
+}
+
+// percentage checks if the current request matches based on a given odds
percentage.
+// The function returns true with a probability equal to the odds percentage.
+//
+// Parameters:
+// - odds: Percentage chance (0-100) of the function returning true.
+//
+// Returns:
+// - true if a generated random number between 1 and 100 (inclusive) is less
than or equal to the odds.
+// - false otherwise.
+func percentage(odds int) bool {
+ if odds <= 0 {
+ return false
+ }
+ // generate rand number in 1-100
+ num := rand.Intn(100) + 1
+ return num <= odds
+}
diff --git a/pixiu/pkg/pluginregistry/registry.go
b/pixiu/pkg/pluginregistry/registry.go
index ddd15793..08e67722 100644
--- a/pixiu/pkg/pluginregistry/registry.go
+++ b/pixiu/pkg/pluginregistry/registry.go
@@ -29,6 +29,7 @@ import (
_ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/authority"
_ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/cors"
_ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/csrf"
+ _ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/failinject"
_ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/header"
_ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/host"
_ "github.com/apache/dubbo-go-pixiu/pixiu/pkg/filter/http/apiconfig"