diff --git a/build/test/client.go b/build/test/client.go index 3b96d0cd2a..1d9216687a 100644 --- a/build/test/client.go +++ b/build/test/client.go @@ -26,16 +26,20 @@ import ( "strings" ) -func egctlCmd(args ...string) *exec.Cmd { +func egctlWithServer(server string, args ...string) *exec.Cmd { egctl := os.Getenv("EGCTL") if egctl == "" { egctl = "egctl" } cmd := exec.Command(egctl, args...) - cmd.Args = append(cmd.Args, "--server", "http://127.0.0.1:12381") + cmd.Args = append(cmd.Args, "--server", server) return cmd } +func egctlCmd(args ...string) *exec.Cmd { + return egctlWithServer("http://127.0.0.1:12381", args...) +} + func runCmd(cmd *exec.Cmd) (string, string, error) { var stdout, stderr bytes.Buffer cmd.Stdout = &stdout @@ -110,3 +114,12 @@ func matchTable(array []string, output string) bool { // Check if the regular expression matches the output string return re.MatchString(output) } + +func egbuilderCmd(args ...string) *exec.Cmd { + egbuilder := os.Getenv("EGBUILDER") + if egbuilder == "" { + egbuilder = "egbuilder" + } + cmd := exec.Command(egbuilder, args...) + return cmd +} diff --git a/build/test/integration_test.go b/build/test/integration_test.go index 60b014d467..498a8a31e2 100644 --- a/build/test/integration_test.go +++ b/build/test/integration_test.go @@ -24,6 +24,7 @@ import ( "io" "net/http" "os" + "os/exec" "path/filepath" "strings" "sync/atomic" @@ -1076,3 +1077,238 @@ filters: assert.Nil(err) assert.Equal("hello from websocket", string(data)) } + +func TestEgbuilder(t *testing.T) { + assert := assert.New(t) + + tempDir, err := os.MkdirTemp("", "easegress-test") + require.Nil(t, err) + defer os.RemoveAll(tempDir) + + // init a new plugin repo + initCmd := egbuilderCmd( + "init", + "--repo", "github.com/test/repo", + "--filters=MyFilter1", + "--controllers=MyController1,MyController2", + ) + initCmd.Dir = tempDir + stdout, stderr, err := runCmd(initCmd) + fmt.Printf("init stdout:\n%s\n", stdout) + fmt.Printf("init stderr:\n%s\n", stderr) + assert.NoError(err) + + // add a new filters and controllers + addCmd := egbuilderCmd( + "add", + "--filters=MyFilter2", + "--controllers=MyController3", + ) + addCmd.Dir = tempDir + stdout, stderr, err = runCmd(addCmd) + fmt.Printf("add stdout:\n%s\n", stdout) + fmt.Printf("add stderr:\n%s\n", stderr) + assert.NoError(err) + + // build easegress with new plugins + buildConfig := ` +plugins: +- module: github.com/test/repo + version: "" + replacement: %s + +output: "%s/easegress-server" +` + buildConfig = fmt.Sprintf(buildConfig, tempDir, tempDir) + err = os.WriteFile(filepath.Join(tempDir, "build.yaml"), []byte(buildConfig), os.ModePerm) + assert.NoError(err) + + buildCmd := egbuilderCmd( + "build", + "-f", + "build.yaml", + ) + buildCmd.Dir = tempDir + stdout, stderr, err = runCmd(buildCmd) + fmt.Printf("build stdout:\n%s\n", stdout) + fmt.Printf("build stderr:\n%s\n", stderr) + assert.NoError(err) + + // run easegress with new plugins + egserverConfig := ` +name: egbuilder +cluster-name: egbuilder-test +cluster-role: primary +cluster: + listen-peer-urls: + - http://localhost:22380 + listen-client-urls: + - http://localhost:22379 + advertise-client-urls: + - http://localhost:22379 + initial-advertise-peer-urls: + - http://localhost:22380 + initial-cluster: + - egbuilder: http://localhost:22380 +api-addr: 127.0.0.1:22381 +` + apiURL := "http://127.0.0.1:22381" + err = os.WriteFile(filepath.Join(tempDir, "config.yaml"), []byte(egserverConfig), os.ModePerm) + assert.Nil(err) + + runEgCmd := exec.Command( + filepath.Join(tempDir, "easegress-server"), + "--config-file", + "config.yaml", + ) + runEgCmd.Dir = tempDir + var stdoutBuf, stderrBuf bytes.Buffer + runEgCmd.Stdout = &stdoutBuf + runEgCmd.Stderr = &stderrBuf + err = runEgCmd.Start() + assert.Nil(err) + defer func() { + err := runEgCmd.Process.Signal(os.Interrupt) + assert.Nil(err) + err = runEgCmd.Wait() + assert.Nil(err) + assert.NotContains(stderrBuf.String(), "panic") + assert.NotContains(stdoutBuf.String(), "panic") + }() + + started := checkServerStart(func() *http.Request { + req, err := http.NewRequest(http.MethodGet, apiURL+"/apis/v2/healthz", nil) + assert.Nil(err) + return req + }) + assert.True(started) + + egctl := func(args ...string) *exec.Cmd { + return egctlWithServer(apiURL, args...) + } + + // create, apply, delete new controllers + controllers := ` +name: c1 +kind: MyController1 + +--- + +name: c2 +kind: MyController2 + +--- + +name: c3 +kind: MyController3 +` + controllerNames := []string{"c1", "c2", "c3"} + controllerKinds := []string{"MyController1", "MyController2", "MyController3"} + + cmd := egctl("create", "-f", "-") + cmd.Stdin = strings.NewReader(controllers) + stdout, stderr, err = runCmd(cmd) + fmt.Printf("egctl create stdout:\n%s\n", stdout) + assert.Contains(stdout, "create MyController1 c1 successfully") + assert.Contains(stdout, "create MyController2 c2 successfully") + assert.Contains(stdout, "create MyController3 c3 successfully") + assert.Empty(stderr) + assert.NoError(err) + + cmd = egctl("get", "all") + stdout, stderr, err = runCmd(cmd) + for i := range controllerNames { + assert.Contains(stdout, controllerNames[i]) + assert.Contains(stdout, controllerKinds[i]) + } + assert.Empty(stderr) + assert.NoError(err) + + cmd = egctl("apply", "-f", "-") + cmd.Stdin = strings.NewReader(controllers) + stdout, stderr, err = runCmd(cmd) + fmt.Printf("egctl apply stdout:\n%s\n", stdout) + assert.Contains(stdout, "update MyController1 c1 successfully") + assert.Contains(stdout, "update MyController2 c2 successfully") + assert.Contains(stdout, "update MyController3 c3 successfully") + assert.Empty(stderr) + assert.NoError(err) + + for i := range controllerNames { + cmd = egctl("delete", controllerKinds[i], controllerNames[i]) + stdout, stderr, err = runCmd(cmd) + fmt.Printf("egctl delete stdout:\n%s\n", stdout) + assert.Contains(stdout, fmt.Sprintf("delete %s %s successfully", controllerKinds[i], controllerNames[i])) + assert.Empty(stderr) + assert.NoError(err) + } + + cmd = egctl("get", "all") + stdout, stderr, err = runCmd(cmd) + for i := range controllerNames { + assert.NotContains(stdout, controllerNames[i]) + assert.NotContains(stdout, controllerKinds[i]) + } + assert.Empty(stderr) + assert.NoError(err) + + // create, apply, delete new filters + filters := ` +name: httpserver +kind: HTTPServer +port: 22399 +rules: +- paths: + - backend: pipeline + +--- + +name: pipeline +kind: Pipeline +flow: +- filter: filter1 +- filter: filter2 +- filter: mock +filters: +- name: filter1 + kind: MyFilter1 +- name: filter2 + kind: MyFilter2 +- name: mock + kind: ResponseBuilder + template: | + statusCode: 200 + body: "body from response builder" +` + + cmd = egctl("create", "-f", "-") + cmd.Stdin = strings.NewReader(filters) + stdout, stderr, err = runCmd(cmd) + fmt.Printf("egctl create stdout:\n%s\n", stdout) + assert.Empty(stderr) + assert.NoError(err) + + cmd = egctl("apply", "-f", "-") + cmd.Stdin = strings.NewReader(filters) + stdout, stderr, err = runCmd(cmd) + fmt.Printf("egctl apply stdout:\n%s\n", stdout) + assert.Empty(stderr) + assert.NoError(err) + + started = checkServerStart(func() *http.Request { + req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:22399", nil) + assert.Nil(err) + return req + }) + assert.True(started) + + req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:22399", nil) + assert.Nil(err) + resp, err := http.DefaultClient.Do(req) + assert.Nil(err) + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + assert.Nil(err) + // get this body means our pipeline is working. + assert.Equal("body from response builder", string(data)) +} diff --git a/build/test/test.sh b/build/test/test.sh index eb903e35a1..e390ad2256 100755 --- a/build/test/test.sh +++ b/build/test/test.sh @@ -28,6 +28,7 @@ pushd $SCRIPTPATH"/../../example" > /dev/null EXAMPLEDIR="$SCRIPTPATH"/../../example PRIMARYDIR=$EXAMPLEDIR"/primary-single" EGCTL=$PRIMARYDIR"/bin/egctl" +EGBUILDER=$PRIMARYDIR"/bin/egbuilder" # target file related define. server="primary-single/bin/easegress-server" @@ -75,7 +76,7 @@ else fi # run go test -env EGCTL=$EGCTL go test -v $SCRIPTPATH +env EGCTL=$EGCTL EGBUILDER=$EGBUILDER go test -v $SCRIPTPATH popd > /dev/null exit 0 diff --git a/cmd/builder/gen/filters.go b/cmd/builder/gen/filters.go index 5e534520b1..7c75420f0b 100644 --- a/cmd/builder/gen/filters.go +++ b/cmd/builder/gen/filters.go @@ -131,7 +131,7 @@ func defineFilterMethods(file *j.File, info *FilterInfo) { nameFunc := receiver() nameFunc.Name = "Name" nameFunc.Returns = []j.Code{j.String()} - nameFunc.Block = []j.Code{j.Return(j.Lit(info.Name))} + nameFunc.Block = []j.Code{j.Return(j.Id(info.ReceiverName).Dot("spec").Dot("Name()"))} file.Add(nameFunc.Def()) // define filter Kind method diff --git a/pkg/object/pipeline/pipeline.go b/pkg/object/pipeline/pipeline.go index e8c342914c..1451759526 100644 --- a/pkg/object/pipeline/pipeline.go +++ b/pkg/object/pipeline/pipeline.go @@ -289,7 +289,7 @@ func (p *Pipeline) reload(previousGeneration *Pipeline) { // add the filter to pipeline, and if the pipeline does not define a // flow, append it to the flow we just created. - p.filters[filter.Name()] = filter + p.filters[spec.Name()] = filter if len(p.spec.Flow) == 0 { flow = append(flow, FlowNode{FilterName: spec.Name()}) }