You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apisix.apache.org by kv...@apache.org on 2020/08/12 02:41:54 UTC

[apisix-control-plane] branch master updated: feat: add yaml to json & schema validation (#6)

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

kvn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-control-plane.git


The following commit(s) were added to refs/heads/master by this push:
     new f8ce5a0  feat: add yaml to json & schema validation (#6)
f8ce5a0 is described below

commit f8ce5a064b620563338109695ca108a1c8a49d01
Author: kv <gx...@163.com>
AuthorDate: Wed Aug 12 10:41:47 2020 +0800

    feat: add yaml to json & schema validation (#6)
    
    * add dependence lib
    
    * test
    
    * feat: yaml to json & jsonschema
    
    * feat: add some deps
    
    * feat: add schema validate
    
    * add ASF header
---
 README.md                          |  19 ++++
 apisix_control_plane_suite_test.go |  29 ++++++
 go.mod                             |   7 ++
 go.sum                             |  69 +++++++++++++
 pkg/yaml/schema.go                 | 196 +++++++++++++++++++++++++++++++++++++
 pkg/yaml/schema_test.go            | 193 ++++++++++++++++++++++++++++++++++++
 pkg/yaml/to_json.go                |  23 +++++
 pkg/yaml/yaml_suite_test.go        |  29 ++++++
 pkg/yaml/yaml_test.go              |  55 +++++++++++
 9 files changed, 620 insertions(+)

diff --git a/README.md b/README.md
index 948c872..3bd6c7b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,22 @@
+<!--
+#
+# 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.
+#
+-->
+
 # apisix-control-plane
 
 ## what is apisix-control-plane?
diff --git a/apisix_control_plane_suite_test.go b/apisix_control_plane_suite_test.go
new file mode 100644
index 0000000..ea669b8
--- /dev/null
+++ b/apisix_control_plane_suite_test.go
@@ -0,0 +1,29 @@
+/*
+ * 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 apisix_control_plane_test
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func TestApisixControlPlane(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "ApisixControlPlane Suite")
+}
diff --git a/go.mod b/go.mod
index 45fd1ed..b82a114 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,10 @@
 module github.com/apache/apisix-control-plane
 
 go 1.13
+
+require (
+	github.com/ghodss/yaml v1.0.0
+	github.com/onsi/ginkgo v1.14.0
+	github.com/onsi/gomega v1.10.1
+	github.com/xeipuuv/gojsonschema v1.2.0
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..774ba0a
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,69 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
+github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/pkg/yaml/schema.go b/pkg/yaml/schema.go
new file mode 100644
index 0000000..5ff51e8
--- /dev/null
+++ b/pkg/yaml/schema.go
@@ -0,0 +1,196 @@
+/*
+ * 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 yaml
+
+import (
+	"fmt"
+	"github.com/xeipuuv/gojsonschema"
+)
+
+// YamlSchema define schema rule
+func YamlSchema() string {
+	return `
+{
+	"type": "object",
+	"properties": {
+		"kind": {
+			"type": "string",
+			"enum": ["Gateway", "Rule", "Destination", "Plugin"]
+		},
+		"name": {
+			"type": "string"
+		},
+		"servers": {
+			"type": "array",
+			"minItems" : 1,
+			"items": {
+				"type": "object",
+				"properties": {
+					"port": {
+						"type": "number",
+						"minimum": 1
+					},
+					"name": {
+						"type": "string"
+					},
+					"protocol": {
+						"type": "string",
+						"enum": ["HTTP", "TCP"]
+					},
+					"hosts": {
+						"type": "array",
+						"items": {
+							"type": "string"
+						}
+					}
+				}
+			}
+		},
+		"hosts": {
+			"type": "array",
+			"items": {
+				"type": "string"
+			}
+		},
+		"gateways": {
+			"type": "array",
+			"items": {
+				"type": "string"
+			}
+		},
+		"http": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"properties": {
+					"route": {
+						"type": "array",
+						"items": {
+							"type": "object",
+							"properties": {
+								"destination": {
+									"type": "object",
+									"properties": {
+										"port": {
+											"type": "number"
+										},
+										"host": {
+											"type": "string"
+										},
+										"subset": {
+											"type": "string"
+										},
+										"weight": {
+											"type": "number"
+										}
+									}
+								}
+							}
+						}
+					},
+					"label": {
+						"type": "object"
+					},
+					"match": {
+						"type": "array",
+						"items": {
+							"type": "object",
+							"properties": {
+								"headers": {
+									"type": "object"
+								}
+							}
+						}
+					}
+				}
+			}
+		},
+		"host": {
+			"type": "string"
+		},
+		"subsets": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"properties": {
+					"name": {
+						"type": "string"
+					},
+					"ips": {
+						"type": "array",
+						"items": {
+							"type": "string"
+						}
+					},
+					"selector": {
+						"type": "object",
+						"properties": {
+							"labels": {
+								"type": "object"
+							}
+						}
+					}
+				}
+			}
+		},
+		"selector": {
+			"type": "object",
+			"properties": {
+				"labels": {
+					"type": "object"
+				}
+			}
+		},
+		"sort": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"properties": {
+					"name": {
+						"type": "string"
+					},
+					"conf": {
+						"type": "object"
+					}
+				}
+			}
+		}
+	},
+	"additionalProperties": true
+}
+`
+}
+
+func Validate(request string) (bool, error) {
+	schemaLoader := gojsonschema.NewStringLoader(YamlSchema())
+	schema, err := gojsonschema.NewSchema(schemaLoader)
+	if err != nil {
+		fmt.Println(err.Error())
+		return false, err
+	}
+	requestLoader := gojsonschema.NewStringLoader(request)
+	result, err := schema.Validate(requestLoader)
+	if err != nil {
+		fmt.Println(err.Error())
+		return false, err
+	}
+	if result.Valid() {
+		return true, nil
+	} else {
+		return false, fmt.Errorf(result.Errors()[0].String())
+	}
+}
diff --git a/pkg/yaml/schema_test.go b/pkg/yaml/schema_test.go
new file mode 100644
index 0000000..b941370
--- /dev/null
+++ b/pkg/yaml/schema_test.go
@@ -0,0 +1,193 @@
+/*
+ * 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 yaml_test
+
+import (
+	"fmt"
+	localYaml "github.com/apache/apisix-control-plane/pkg/yaml"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("Schema", func() {
+	// gateway
+	Describe("Gateway schema", func() {
+		var okGateway string
+		BeforeEach(func() {
+			okGateway = `
+kind: Gateway
+name: foo-gw
+servers:
+ - port: 80
+   name: http
+   protocol: HTTP
+   hosts:
+   - "a.foo.com"
+   - "b.foo.com"
+`
+			fmt.Println(okGateway)
+		})
+		Context("Gateway schema check ok", func() {
+			It("Gateway yaml is ok", func() {
+				fmt.Println(okGateway)
+				fmt.Println(2)
+				if b, err := localYaml.ToJson(okGateway); err != nil {
+					fmt.Println(err.Error())
+					panic(err.Error())
+				} else {
+					fmt.Println(string(b))
+					result, err := localYaml.Validate(string(b))
+					Expect(err).NotTo(HaveOccurred())
+					Expect(result).To(Equal(true))
+				}
+			})
+		})
+	})
+
+	// rule
+	Describe("Rule schema", func() {
+		var okRule string
+		BeforeEach(func() {
+			okRule = `
+kind: Rule
+name: xxx-rules
+hosts:
+- "foo.com"
+gateways:
+- foo-gw
+http:
+- route:
+  - destination:
+     port: 28002
+     host: foo-server
+     subset: foo-v1
+     weight: 10
+  label:
+    app: foo 
+    version: v1
+  match: 
+  - headers:
+     product_id:
+       exact: v1
+- route:
+  - destination:
+       port: 28002
+       host: foo-server
+       subset: v2
+  label:
+    app: foo 
+    version: v2
+`
+			fmt.Println(okRule)
+		})
+		Context("Rule schema check ok", func() {
+			It("Rule yaml is ok", func() {
+				fmt.Println(okRule)
+				if b, err := localYaml.ToJson(okRule); err != nil {
+					fmt.Println(err.Error())
+					panic(err.Error())
+				} else {
+					fmt.Println(string(b))
+					result, err := localYaml.Validate(string(b))
+					Expect(err).NotTo(HaveOccurred())
+					Expect(result).To(Equal(true))
+				}
+			})
+		})
+	})
+
+	// destination
+	Describe("Destination schema", func() {
+		var okTarget string
+		BeforeEach(func() {
+			okTarget = `
+kind: Destination
+name: foo-dest
+host: foo-server
+subsets: 
+- name: foo-v1 
+  ips:
+  - 127.0.0.1
+  - 127.0.0.2
+- name: v2
+  selector:
+    labels:
+      tag: v2
+`
+			fmt.Println(okTarget)
+		})
+		Context("Destination schema check ok", func() {
+			It("Destination yaml is ok", func() {
+				fmt.Println(okTarget)
+				if b, err := localYaml.ToJson(okTarget); err != nil {
+					fmt.Println(err.Error())
+					panic(err.Error())
+				} else {
+					fmt.Println(string(b))
+					result, err := localYaml.Validate(string(b))
+					if err != nil {
+						fmt.Println(err.Error())
+					}
+					Expect(err).NotTo(HaveOccurred())
+					Expect(result).To(Equal(true))
+				}
+			})
+		})
+	})
+
+	// plugin
+	Describe("Plugin schema", func() {
+		var okPlugin string
+		BeforeEach(func() {
+			okPlugin = `
+kind: Plugin
+selector: 
+  labels:
+     app: foo 
+sort:
+- name: proxy-rewrite
+  conf:
+    uri: "/test/home.html"
+    scheme: "http"
+    host: "baidu.com"
+    headers: 
+      X-Api-Version: "v1"
+      X-Api-Engine: "apisix"
+      X-Api-useless: ""
+- name: prometheus
+`
+			fmt.Println(okPlugin)
+		})
+		Context("Plugin schema check ok", func() {
+			It("Plugin yaml is ok", func() {
+				fmt.Println(okPlugin)
+				if b, err := localYaml.ToJson(okPlugin); err != nil {
+					fmt.Println(err.Error())
+					panic(err.Error())
+				} else {
+					fmt.Println(string(b))
+					result, err := localYaml.Validate(string(b))
+					if err != nil {
+						fmt.Println(err.Error())
+					}
+					Expect(err).NotTo(HaveOccurred())
+					Expect(result).To(Equal(true))
+				}
+			})
+		})
+	})
+})
diff --git a/pkg/yaml/to_json.go b/pkg/yaml/to_json.go
new file mode 100644
index 0000000..3ffa17e
--- /dev/null
+++ b/pkg/yaml/to_json.go
@@ -0,0 +1,23 @@
+/*
+ * 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 yaml
+
+import "github.com/ghodss/yaml"
+
+func ToJson(y string) ([]byte, error) {
+	return yaml.YAMLToJSON([]byte(y))
+}
diff --git a/pkg/yaml/yaml_suite_test.go b/pkg/yaml/yaml_suite_test.go
new file mode 100644
index 0000000..59e4d7e
--- /dev/null
+++ b/pkg/yaml/yaml_suite_test.go
@@ -0,0 +1,29 @@
+/*
+ * 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 yaml_test
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func TestYaml(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "Yaml Suite")
+}
diff --git a/pkg/yaml/yaml_test.go b/pkg/yaml/yaml_test.go
new file mode 100644
index 0000000..7a62731
--- /dev/null
+++ b/pkg/yaml/yaml_test.go
@@ -0,0 +1,55 @@
+/*
+ * 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 yaml_test
+
+import (
+	"fmt"
+
+	"github.com/ghodss/yaml"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("Yaml", func() {
+	Describe("yaml & json", func() {
+		var b []byte
+		BeforeEach(func() {
+			b = []byte(`{"name": "John", "age": 30}`)
+			fmt.Println("BeforeEach executed")
+		})
+		Context("json to yaml", func() {
+			It("json to yaml no error", func() {
+				fmt.Println(string(b))
+				y, err := yaml.JSONToYAML(b)
+				fmt.Println(string(y))
+				Expect(err).NotTo(HaveOccurred())
+			})
+		})
+
+		Context("yaml to json", func() {
+
+			It("yaml to json no error", func() {
+				fmt.Println(5)
+				y, _ := yaml.JSONToYAML(b)
+				y2, err := yaml.YAMLToJSON(y)
+				fmt.Println(string(y2))
+				Expect(err).NotTo(HaveOccurred())
+			})
+		})
+
+	})
+})