You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by ma...@apache.org on 2023/09/24 06:52:26 UTC

[dubbo-go-pixiu] branch develop updated: feat(failinject): add failinject feature (#571)

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 <i...@marlon.life>
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 <36...@users.noreply.github.com>
---
 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"