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"

Reply via email to