Jelajahi Sumber

feat(cli): add rule validating (#2160)

Signed-off-by: Rui-Gan <1171530954@qq.com>
Regina 1 tahun lalu
induk
melakukan
3cea3c8712

+ 58 - 0
cmd/kuiper/main.go

@@ -941,6 +941,64 @@ func main() {
 			},
 		},
 		{
+			Name:    "validate",
+			Aliases: []string{"validate"},
+			Usage:   "validate rule $rule_name [$rule_json | -f $rule_def_file]",
+			Subcommands: []cli.Command{
+				{
+					Name:  "rule",
+					Usage: "validate rule $rule_name [$rule_json | -f $rule_def_file]",
+					Flags: []cli.Flag{
+						cli.StringFlag{
+							Name:     "file, f",
+							Usage:    "the location of rule definition file",
+							FilePath: "/home/myrule.txt",
+						},
+					},
+					Action: func(c *cli.Context) error {
+						sfile := c.String("file")
+						if sfile != "" {
+							if rule, err := readDef(sfile, "rule"); err != nil {
+								fmt.Printf("%s", err)
+								return nil
+							} else {
+								if len(c.Args()) != 1 {
+									fmt.Printf("Expect rule name.\n")
+									return nil
+								}
+								rname := c.Args()[0]
+								var reply string
+								args := &model.RPCArgDesc{Name: rname, Json: string(rule)}
+								err = client.Call("Server.ValidateRule", args, &reply)
+								if err != nil {
+									fmt.Println(err)
+								} else {
+									fmt.Println(reply)
+								}
+							}
+							return nil
+						} else {
+							if len(c.Args()) != 2 {
+								fmt.Printf("Expect rule name and json.\nBut found %d args:%s.\n", len(c.Args()), c.Args())
+								return nil
+							}
+							rname := c.Args()[0]
+							rjson := c.Args()[1]
+							var reply string
+							args := &model.RPCArgDesc{Name: rname, Json: rjson}
+							err = client.Call("Server.ValidateRule", args, &reply)
+							if err != nil {
+								fmt.Println(err)
+							} else {
+								fmt.Println(reply)
+							}
+							return nil
+						}
+					},
+				},
+			},
+		},
+		{
 			Name:    "register",
 			Aliases: []string{"register"},
 			Usage:   "register plugin function $plugin_name [$plugin_json | -f plugin_def_file]",

+ 49 - 0
docs/en_US/api/cli/rules.md

@@ -222,3 +222,52 @@ Sample result:
   }
 }
 ```
+
+## validate a rule
+
+The command is used for validating a rule.  The rule's definition is specified with JSON format, read [rule](../../guide/rules/overview.md) for more detailed information.
+
+```shell
+validate rule $rule_name '$rule_json' | validate rule $rule_name -f $rule_def_file
+```
+
+There are two ways to validate rules, which are the same as the two ways to create rules.
+
+- Specify the rule definition in command line.
+
+示例:
+
+```shell
+# bin/kuiper validate rule rule1 '{"sql": "SELECT * from demo","actions": [{"log":  {}},{"mqtt":  {"server":"tcp://127.0.0.1:1883", "topic":"demoSink"}}]}'
+The rule has been successfully validated and is confirmed to be correct.
+```
+
+The command validate a rule named `rule1`.
+
+- Specify the rule definition in file.
+
+Sample:
+
+```shell
+# bin/kuiper validate rule rule1 -f /tmp/rule.txt
+The rule has been successfully validated and is confirmed to be correct.
+```
+
+Below is the contents of `rule.txt`.
+
+```json
+{
+  "sql": "SELECT * from demo",
+  "actions": [
+    {
+      "log": {}
+    },
+    {
+      "mqtt": {
+        "server": "tcp://127.0.0.1:1883",
+        "topic": "demoSink"
+      }
+    }
+  ]
+}
+```

+ 49 - 0
docs/zh_CN/api/cli/rules.md

@@ -193,3 +193,52 @@ getstatus rule $rule_name
     ...
 }
 ```
+
+## 验证规则
+
+如下命令用于验证规则。 规则的定义以 JSON 格式指定,请阅读 [规则](../../guide/rules/overview.md) 以获取更多详细信息。
+
+```shell
+validate rule $rule_name '$rule_json' | validate rule $rule_name -f $rule_def_file
+```
+
+可以通过两种方式验证规则,和创建规则的两种方式相同。
+
+- 在命令行中指定规则定义。
+
+示例:
+
+```shell
+# bin/kuiper validate rule rule1 '{"sql": "SELECT * from demo","actions": [{"log":  {}},{"mqtt":  {"server":"tcp://127.0.0.1:1883", "topic":"demoSink"}}]}'
+The rule has been successfully validated and is confirmed to be correct.
+```
+
+该命令验证一个名为 `rule1` 的规则。
+
+- 在文件中明确规则定义。
+
+示例:
+
+```shell
+# bin/kuiper validate rule rule1 -f /tmp/rule.txt
+The rule has been successfully validated and is confirmed to be correct.
+```
+
+以下是 `rule.txt` 的内容。
+
+```json
+{
+  "sql": "SELECT * from demo",
+  "actions": [
+    {
+      "log": {}
+    },
+    {
+      "mqtt": {
+        "server": "tcp://127.0.0.1:1883",
+        "topic": "demoSink"
+      }
+    }
+  ]
+}
+```

+ 10 - 0
internal/server/rpc.go

@@ -248,6 +248,16 @@ func (t *Server) DropRule(name string, reply *string) error {
 	return nil
 }
 
+func (t *Server) ValidateRule(rule *model.RPCArgDesc, reply *string) error {
+	s, err := validateRule(rule.Name, rule.Json)
+	if s {
+		*reply = "The rule has been successfully validated and is confirmed to be correct."
+	} else {
+		*reply = err.Error()
+	}
+	return nil
+}
+
 func (t *Server) Import(file string, reply *string) error {
 	f, err := os.Open(file)
 	if err != nil {

+ 26 - 0
internal/server/rpc_test.go

@@ -95,6 +95,32 @@ func (suite *ServerTestSuite) TestRule() {
 	}`
 	ruleId := "myRule"
 	args := &model.RPCArgDesc{Name: ruleId, Json: rule}
+	err = suite.s.ValidateRule(args, &reply)
+	assert.Nil(suite.T(), err)
+	assert.Equal(suite.T(), "The rule has been successfully validated and is confirmed to be correct.", reply)
+
+	reply = ""
+	rule = `{
+			  "sql": "SELECT * from test;"
+			}`
+	args = &model.RPCArgDesc{Name: ruleId, Json: rule}
+	err = suite.s.ValidateRule(args, &reply)
+	assert.Nil(suite.T(), err)
+	assert.Equal(suite.T(), "invalid rule json: Missing rule actions.", reply)
+
+	reply = ""
+	rule = `{
+			  "sql": "SELECT * from test;",
+			  "actions": [{
+				"file": {
+				  "path": "../internal/server/rpc_test_data/data/result.txt",
+				  "interval": 5000,
+				  "fileType": "lines",
+				  "format": "json"
+				}
+			  }]
+	}`
+	args = &model.RPCArgDesc{Name: ruleId, Json: rule}
 	err = suite.s.CreateRule(args, &reply)
 	assert.Nil(suite.T(), err)
 	assert.Equal(suite.T(), "Rule myRule was created successfully, please use 'bin/kuiper getstatus rule myRule' command to get rule status.", reply)