You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2022/08/23 03:19:53 UTC

[servicecomb-service-center] branch master updated: [fix]failed to create match-group policy (#1335)

This is an automated email from the ASF dual-hosted git repository.

littlecui pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git


The following commit(s) were added to refs/heads/master by this push:
     new e01d4859 [fix]failed to create match-group policy (#1335)
e01d4859 is described below

commit e01d48593514c1cd571a479ceb2f5673b65e6ecd
Author: little-cui <su...@qq.com>
AuthorDate: Tue Aug 23 11:19:49 2022 +0800

    [fix]failed to create match-group policy (#1335)
    
    * [fix]failed to create match-group policy
    
    * [fix]failed to create match-group policy
---
 server/ext/policy/builtin.go      | 199 ++++++++++++++++++++++++++++++++++++++
 server/ext/policy/builtin_test.go | 144 +++++++++++++++++++++++++++
 server/ext/policy/buitin.go       |  68 -------------
 server/service/grc/policy.go      |  19 +---
 server/service/grc/validate.go    | 114 ----------------------
 5 files changed, 347 insertions(+), 197 deletions(-)

diff --git a/server/ext/policy/builtin.go b/server/ext/policy/builtin.go
new file mode 100644
index 00000000..b32c34ab
--- /dev/null
+++ b/server/ext/policy/builtin.go
@@ -0,0 +1,199 @@
+/*
+ * 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 policy
+
+import (
+	"github.com/apache/servicecomb-service-center/server/service/grc"
+	"k8s.io/kube-openapi/pkg/validation/spec"
+)
+
+var (
+	notEmpty         = int64(1)
+	notNegative      = float64(0)
+	matchGroupSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"matches", "alias"},
+			Properties: map[string]spec.Schema{
+				"alias": {
+					SchemaProps: spec.SchemaProps{
+						Type:      []string{"string"},
+						MinLength: &notEmpty,
+					},
+				},
+				"matches": {
+					SchemaProps: spec.SchemaProps{
+						Type:     []string{"array"},
+						MinItems: &notEmpty,
+						Items: &spec.SchemaOrArray{
+							Schema: &spec.Schema{
+								SchemaProps: spec.SchemaProps{
+									Type:     []string{"object"},
+									Required: []string{"name"},
+									Properties: map[string]spec.Schema{
+										"name": {
+											SchemaProps: spec.SchemaProps{
+												Type:      []string{"string"},
+												MinLength: &notEmpty,
+											},
+										},
+										"apiPath": {
+											SchemaProps: spec.SchemaProps{
+												Type:      []string{"string"},
+												MinLength: &notEmpty,
+											},
+										},
+										"method": {
+											SchemaProps: spec.SchemaProps{
+												Type:     []string{"array"},
+												MinItems: &notEmpty,
+												Items: &spec.SchemaOrArray{
+													Schema: &spec.Schema{
+														SchemaProps: spec.SchemaProps{
+															Type: []string{"string"},
+															Enum: []interface{}{"GET", "POST", "DELETE", "PUT", "PATCH"},
+														},
+													},
+												},
+											},
+										},
+										"headers": {
+											SchemaProps: spec.SchemaProps{
+												Type:          []string{"object"},
+												MinProperties: &notEmpty,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}}
+	retrySchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:          []string{"object"},
+			MinProperties: &notEmpty,
+			Properties: map[string]spec.Schema{
+				"maxAttempts": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"integer"},
+						Minimum: &notNegative,
+					},
+				},
+				"retryOnSame": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"integer"},
+						Minimum: &notNegative,
+					},
+				},
+			},
+		},
+	}
+	rateLimitingSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"rate"},
+			Properties: map[string]spec.Schema{
+				"rate": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"number"},
+						Minimum: &notNegative,
+					},
+				},
+			},
+		},
+	}
+	loadbalanceSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"rule"},
+			Properties: map[string]spec.Schema{
+				"rule": {
+					SchemaProps: spec.SchemaProps{
+						Type:      []string{"string"},
+						MinLength: &notEmpty,
+					},
+				},
+			},
+		}}
+	circuitBreakerSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"minimumNumberOfCalls"},
+			Properties: map[string]spec.Schema{
+				"minimumNumberOfCalls": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"integer"},
+						Minimum: &notNegative,
+					},
+				},
+			},
+		}}
+	instanceIsolationSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"minimumNumberOfCalls"},
+			Properties: map[string]spec.Schema{
+				"minimumNumberOfCalls": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"integer"},
+						Minimum: &notNegative,
+					},
+				},
+			},
+		}}
+	faultInjectionSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"percentage"},
+			Properties: map[string]spec.Schema{
+				"percentage": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"number"},
+						Minimum: &notNegative,
+					},
+				},
+			},
+		}}
+	bulkheadSchema = &spec.Schema{
+		SchemaProps: spec.SchemaProps{
+			Type:     []string{"object"},
+			Required: []string{"maxConcurrentCalls"},
+			Properties: map[string]spec.Schema{
+				"maxConcurrentCalls": {
+					SchemaProps: spec.SchemaProps{
+						Type:    []string{"integer"},
+						Minimum: &notNegative,
+					},
+				},
+			},
+		}}
+)
+
+func init() {
+	grc.RegisterPolicySchema("match-group", matchGroupSchema)
+	grc.RegisterPolicySchema("retry", retrySchema)
+	grc.RegisterPolicySchema("rate-limiting", rateLimitingSchema)
+	grc.RegisterPolicySchema("loadbalance", loadbalanceSchema)
+	grc.RegisterPolicySchema("circuit-breaker", circuitBreakerSchema)
+	grc.RegisterPolicySchema("instance-isolation", instanceIsolationSchema)
+	grc.RegisterPolicySchema("fault-injection", faultInjectionSchema)
+	grc.RegisterPolicySchema("bulkhead", bulkheadSchema)
+}
diff --git a/server/ext/policy/builtin_test.go b/server/ext/policy/builtin_test.go
new file mode 100644
index 00000000..c0136edf
--- /dev/null
+++ b/server/ext/policy/builtin_test.go
@@ -0,0 +1,144 @@
+/*
+ * 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 policy
+
+import (
+	"testing"
+
+	"github.com/apache/servicecomb-service-center/server/service/grc"
+)
+
+func TestValidatePolicySpec(t *testing.T) {
+	type args struct {
+		kind string
+		spec interface{}
+	}
+
+	kindMatchGroup := "match-group"
+	kindRetry := "retry"
+	kindRateLimiting := "rate-limiting"
+	kindLoadbalance := "loadbalance"
+	kindCircuitBreaker := "circuit-breaker"
+	kindInstanceIsolation := "instance-isolation"
+	kindFaultInjection := "fault-injection"
+	kindBulkhead := "bulkhead"
+
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{"undefined", args{kind: "undefined", spec: map[string]interface{}{}}, true},
+
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: ""}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"": nil}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": nil}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{}}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{nil}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": ""},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1"},
+		}, "alias": "1"}}, false},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1"},
+		}, "alias": ""}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "apiPath": ""},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "apiPath": "1"},
+		}, "alias": "1"}}, false},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "headers": ""},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "headers": map[string]interface{}{}},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "headers": map[string]interface{}{"k": "v"}},
+		}, "alias": "1"}}, false},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "method": []interface{}{}},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "method": []interface{}{1}},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "method": []interface{}{""}},
+		}, "alias": "1"}}, true},
+		{kindMatchGroup, args{kind: kindMatchGroup, spec: map[string]interface{}{"matches": []interface{}{
+			map[string]interface{}{"name": "1", "method": []interface{}{"GET"}},
+		}, "alias": "1"}}, false},
+
+		{kindRetry, args{kind: kindRetry, spec: ""}, true},
+		{kindRetry, args{kind: kindRetry, spec: map[string]interface{}{}}, true},
+		{kindRetry, args{kind: kindRetry, spec: map[string]interface{}{"maxAttempts": 3}}, false},
+
+		{kindRateLimiting, args{kind: kindRateLimiting, spec: ""}, true},
+		{kindRateLimiting, args{kind: kindRateLimiting, spec: map[string]interface{}{}}, true},
+		{kindRateLimiting, args{kind: kindRateLimiting, spec: map[string]interface{}{"rate": -1}}, true},
+		{kindRateLimiting, args{kind: kindRateLimiting, spec: map[string]interface{}{"rate": 1}}, false},
+		{kindRateLimiting, args{kind: kindRateLimiting, spec: map[string]interface{}{"rate": 0.5}}, false},
+		{kindRateLimiting, args{kind: kindRateLimiting, spec: map[string]interface{}{"rate": "1"}}, true},
+
+		{kindLoadbalance, args{kind: kindLoadbalance, spec: ""}, true},
+		{kindLoadbalance, args{kind: kindLoadbalance, spec: map[string]interface{}{}}, true},
+		{kindLoadbalance, args{kind: kindLoadbalance, spec: map[string]interface{}{"rule": 1}}, true},
+		{kindLoadbalance, args{kind: kindLoadbalance, spec: map[string]interface{}{"rule": ""}}, true},
+		{kindLoadbalance, args{kind: kindLoadbalance, spec: map[string]interface{}{"rule": "1"}}, false},
+
+		{kindCircuitBreaker, args{kind: kindCircuitBreaker, spec: ""}, true},
+		{kindCircuitBreaker, args{kind: kindCircuitBreaker, spec: map[string]interface{}{}}, true},
+		{kindCircuitBreaker, args{kind: kindCircuitBreaker, spec: map[string]interface{}{"minimumNumberOfCalls": -1}}, true},
+		{kindCircuitBreaker, args{kind: kindCircuitBreaker, spec: map[string]interface{}{"minimumNumberOfCalls": 1}}, false},
+		{kindCircuitBreaker, args{kind: kindCircuitBreaker, spec: map[string]interface{}{"minimumNumberOfCalls": "1"}}, true},
+
+		{kindInstanceIsolation, args{kind: kindInstanceIsolation, spec: ""}, true},
+		{kindInstanceIsolation, args{kind: kindInstanceIsolation, spec: map[string]interface{}{}}, true},
+		{kindInstanceIsolation, args{kind: kindInstanceIsolation, spec: map[string]interface{}{"minimumNumberOfCalls": -1}}, true},
+		{kindInstanceIsolation, args{kind: kindInstanceIsolation, spec: map[string]interface{}{"minimumNumberOfCalls": 1}}, false},
+		{kindInstanceIsolation, args{kind: kindInstanceIsolation, spec: map[string]interface{}{"minimumNumberOfCalls": "1"}}, true},
+
+		{kindFaultInjection, args{kind: kindFaultInjection, spec: ""}, true},
+		{kindFaultInjection, args{kind: kindFaultInjection, spec: map[string]interface{}{}}, true},
+		{kindFaultInjection, args{kind: kindFaultInjection, spec: map[string]interface{}{"percentage": -1}}, true},
+		{kindFaultInjection, args{kind: kindFaultInjection, spec: map[string]interface{}{"percentage": 1}}, false},
+		{kindFaultInjection, args{kind: kindFaultInjection, spec: map[string]interface{}{"percentage": 0.5}}, false},
+		{kindFaultInjection, args{kind: kindFaultInjection, spec: map[string]interface{}{"percentage": "1"}}, true},
+
+		{kindBulkhead, args{kind: kindBulkhead, spec: ""}, true},
+		{kindBulkhead, args{kind: kindBulkhead, spec: map[string]interface{}{}}, true},
+		{kindBulkhead, args{kind: kindBulkhead, spec: map[string]interface{}{"maxConcurrentCalls": -1}}, true},
+		{kindBulkhead, args{kind: kindBulkhead, spec: map[string]interface{}{"maxConcurrentCalls": 1}}, false},
+		{kindBulkhead, args{kind: kindBulkhead, spec: map[string]interface{}{"maxConcurrentCalls": "1"}}, true},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := grc.ValidatePolicySpec(tt.args.kind, tt.args.spec); (err != nil) != tt.wantErr {
+				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
diff --git a/server/ext/policy/buitin.go b/server/ext/policy/buitin.go
deleted file mode 100644
index 90e2e42e..00000000
--- a/server/ext/policy/buitin.go
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 policy
-
-import (
-	"github.com/apache/servicecomb-service-center/server/service/grc"
-	"k8s.io/kube-openapi/pkg/validation/spec"
-)
-
-func init() {
-	grc.RegisterPolicySchema("loadbalance", &spec.Schema{
-		SchemaProps: spec.SchemaProps{
-			Type:     []string{"object"},
-			Required: []string{"rule"},
-			Properties: map[string]spec.Schema{
-				"rule": {
-					SchemaProps: spec.SchemaProps{Type: []string{"string"}}},
-			},
-		}})
-	grc.RegisterPolicySchema("circuitBreaker", &spec.Schema{
-		SchemaProps: spec.SchemaProps{
-			Type: []string{"object"},
-			Properties: map[string]spec.Schema{
-				"minimumNumberOfCalls": {
-					SchemaProps: spec.SchemaProps{Type: []string{"integer"}}},
-			},
-		}})
-	grc.RegisterPolicySchema("instanceIsolation", &spec.Schema{
-		SchemaProps: spec.SchemaProps{
-			Type: []string{"object"},
-			Properties: map[string]spec.Schema{
-				"minimumNumberOfCalls": {
-					SchemaProps: spec.SchemaProps{Type: []string{"integer"}}},
-			},
-		}})
-	grc.RegisterPolicySchema("faultInjection", &spec.Schema{
-		SchemaProps: spec.SchemaProps{
-			Type: []string{"object"},
-			Properties: map[string]spec.Schema{
-				"percentage": {
-					SchemaProps: spec.SchemaProps{Type: []string{"integer"}}},
-			},
-		}})
-	grc.RegisterPolicySchema("bulkhead", &spec.Schema{
-		SchemaProps: spec.SchemaProps{
-			Type: []string{"object"},
-			Properties: map[string]spec.Schema{
-				"maxConcurrentCalls": {
-					SchemaProps: spec.SchemaProps{Type: []string{"integer"}}},
-			},
-		}})
-
-}
diff --git a/server/service/grc/policy.go b/server/service/grc/policy.go
index a81ebf1f..c22e6639 100644
--- a/server/service/grc/policy.go
+++ b/server/service/grc/policy.go
@@ -44,31 +44,20 @@ func RegisterPolicySchema(kind string, schema *spec.Schema) {
 }
 
 // ValidatePolicySpec validates spec attributes
-// it first us legacy mechanism Validate 3 kinds of policy.
-// then it use new mechanism to validate all of other policy
 func ValidatePolicySpec(kind string, spec interface{}) error {
-	// TODO this legacy API should be removed. after 3 kinds of policy schema is registered by "RegisterPolicySchema"
-	err := Validate(kind, spec)
-	if err != nil {
-		return err
-	}
 	schema, ok := policySchemas[kind]
 	if !ok {
 		log.Warn(fmt.Sprintf("can not recognize policy %s", kind))
 		return &ErrIllegalItem{"not support kind yet", kind}
 	}
-	validator := validate.NewSchemaValidator(schema, nil, "", strfmt.Default)
+	validator := validate.NewSchemaValidator(schema, nil, kind, strfmt.Default)
 	errs := validator.Validate(spec).Errors
 	if len(errs) != 0 {
 		var str []string
-		for i, err := range errs {
-			if i != 0 {
-				str = append(str, ";", err.Error())
-			} else {
-				str = append(str, err.Error())
-			}
+		for _, err := range errs {
+			str = append(str, err.Error())
 		}
-		return errors.New(strings.Join(str, ";"))
+		return errors.New(strings.Join(str, "; "))
 	}
 	return nil
 }
diff --git a/server/service/grc/validate.go b/server/service/grc/validate.go
index f19c40df..26ed0870 100644
--- a/server/service/grc/validate.go
+++ b/server/service/grc/validate.go
@@ -30,10 +30,6 @@ const (
 	KeyApp          = "app"
 	KeyEnvironment  = "environment"
 	EnvAll          = "all"
-	Alias           = "alias"
-	Method          = "method"
-	Matches         = "matches"
-	Rules           = "rules"
 )
 
 type ErrIllegalItem struct {
@@ -41,116 +37,6 @@ type ErrIllegalItem struct {
 	val interface{}
 }
 
-var (
-	methodSet map[string]bool
-)
-
 func (e *ErrIllegalItem) Error() string {
 	return fmt.Sprintf("illegal item : %v , msg: %s", e.val, e.err)
 }
-
-// Validate is a legacy API, it is not extensible due to its bad design pattern
-// Please use grc.RegisterPolicySchema
-// it only response for validate 3 kinds of policy. if it is not this 3 kinds, it will not return error,
-// it return nil error, and let grc.ValidatePolicySpec to do the job
-func Validate(kind string, spec interface{}) error {
-	switch kind {
-	case "match-group":
-		return matchValidate(spec)
-	case "retry":
-		return retryValidate(spec)
-	case "rate-limiting":
-		return rateLimitingValidate(spec)
-	default:
-		return nil
-	}
-}
-
-func matchValidate(val interface{}) error {
-	spec, ok := val.(map[string]interface{})
-	if !ok {
-		return &ErrIllegalItem{"can not cast to map", val}
-	}
-	if spec[Matches] == nil {
-		return nil
-	}
-	alias, ok := spec[Alias].(string)
-	if !ok {
-		return &ErrIllegalItem{"alias must be string", alias}
-	}
-	matches, ok := spec[Matches].([]interface{})
-	if !ok {
-		return &ErrIllegalItem{"don't have matches", spec}
-	}
-	for _, match := range matches {
-		match, ok := match.(map[string]interface{})
-		if !ok {
-			return &ErrIllegalItem{"match can not cast to map", match}
-		}
-		if match["name"] == nil {
-			return &ErrIllegalItem{"match's name can not be null", match}
-		}
-		if match["apiPath"] == nil && match["headers"] == nil && match[Method] == nil {
-			return &ErrIllegalItem{"match must have a match item [apiPath/headers/methods]", match}
-		}
-		//apiPath & headers do not check
-		if match[Method] != nil {
-			methods, ok := match[Method].([]interface{})
-			if !ok {
-				return &ErrIllegalItem{"methods must be a list", match}
-			}
-			for _, method := range methods {
-				methodStr, ok := method.(string)
-				if !ok {
-					return &ErrIllegalItem{"method must be a string", method}
-				}
-				if !methodSet[methodStr] {
-					return &ErrIllegalItem{"method must be one of the GET/POST/PUT/DELETE/PATCH", method}
-				}
-			}
-		}
-	}
-	return nil
-}
-
-func retryValidate(val interface{}) error {
-	err := policyValidate(val)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func rateLimitingValidate(val interface{}) error {
-	err := policyValidate(val)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func policyValidate(val interface{}) error {
-	spec, ok := val.(map[string]interface{})
-	if !ok {
-		return &ErrIllegalItem{"policy can not cast to map", val}
-	}
-	if spec[Rules] != nil {
-		rules, ok := spec[Rules].(map[string]interface{})
-		if !ok {
-			return &ErrIllegalItem{"policy's rules can not cast to map", spec}
-		}
-		if "" == rules["match"] {
-			return &ErrIllegalItem{"policy's rules match can not be nil", spec}
-		}
-	}
-	return nil
-}
-
-func init() {
-	methodSet = make(map[string]bool)
-	methodSet["GET"] = true
-	methodSet["POST"] = true
-	methodSet["DELETE"] = true
-	methodSet["PUT"] = true
-	methodSet["PATCH"] = true
-}