Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add egctl edit, egctl logs, update egctl create cmd #1067

Merged
merged 15 commits into from
Aug 31, 2023
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@ filters:
The pipeline means it will forward traffic to 3 backend endpoints, using the
`roundRobin` load balance policy.

You can also create them using `egctl create httpproxy` command.
```bash
egctl create httpproxy demo --port 10080 \
--rule="/pipeline=http:https://127.0.0.1:9095,http:https://127.0.0.1:9096,http:https://127.0.0.1:9097"
```
this command will create `HTTPServer` `demo-server` and `Pipeline` `demo-pipeline-0` which work exactly same to `server-demo` and `pipeline-demo`. See more about [`egctl create httpproxy`](./doc/egctl-cheat-sheet.md#create-httpproxy).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

propose not adding -server suffix to the name, user may get confused what he/she has created.
for the pipeline names, also propose not using the pipeline-x suffixes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea. I will update that!

Additionally, we provide a [dashboard](https://cloud.megaease.com) that
streamlines the aforementioned steps, this intuitive tool can help you create,
manage HTTPServers, Pipelines and other Easegress configuration.
Expand Down
102 changes: 102 additions & 0 deletions build/test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package test

import (
"bytes"
"context"
"fmt"
"io"
Expand Down Expand Up @@ -535,3 +536,104 @@ list:
err = deleteResource("cdk", "custom-data-kind1")
assert.NoError(err)
}

func TestCreateHTTPProxy(t *testing.T) {
assert := assert.New(t)

for i, port := range []int{9096, 9097, 9098} {
currentPort := port
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello from backend %d", currentPort)
})

server := startServer(currentPort, mux)
defer server.Shutdown(context.Background())
started := checkServerStart(t, func() *http.Request {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http:https://127.0.0.1:%d", currentPort), nil)
require.Nil(t, err)
return req
})
require.True(t, started, i)
}

cmd := egctlCmd(
"create",
"httpproxy",
"http-proxy-test",
"--port", "10080",
"--rule",
"/pipeline=http:https://127.0.0.1:9096",
"--rule",
"/barz=http:https://127.0.0.1:9097",
"--rule",
"/bar*=http:https://127.0.0.1:9098",
)
_, stderr, err := runCmd(cmd)
assert.NoError(err)
assert.Empty(stderr)

output, err := getResource("httpserver")
assert.NoError(err)
assert.True(strings.Contains(output, "http-proxy-test-server"))

output, err = getResource("pipeline")
assert.NoError(err)
assert.True(strings.Contains(output, "http-proxy-test-pipeline-0"))

testFn := func(p string, expected string) {
req, err := http.NewRequest(http.MethodGet, "http:https://127.0.0.1:10080"+p, nil)
assert.Nil(err, p)
resp, err := http.DefaultClient.Do(req)
assert.Nil(err, p)
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
assert.Nil(err, p)
assert.Equal(expected, string(data), p)
}

testFn("/pipeline", "hello from backend 9096")
testFn("/barz", "hello from backend 9097")
testFn("/bar-prefix", "hello from backend 9098")
}

func TestLogs(t *testing.T) {
assert := assert.New(t)

{
// test egctl logs --tail n
cmd := egctlCmd("logs", "--tail", "5")
output, stderr, err := runCmd(cmd)
assert.NoError(err)
assert.Empty(stderr)
assert.True(strings.Contains(output, "INFO"))
assert.True(strings.Contains(output, ".go"), "should contain go file in log")
lines := strings.Split(strings.TrimSpace(output), "\n")
assert.Len(lines, 5)
}
{
// test egctl logs -f
cmd := egctlCmd("logs", "-f", "--tail", "0")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Start()
assert.NoError(err)

// check if new logs are printed
yamlStr := `
kind: HTTPServer
name: test-egctl-logs
port: 12345
rules:
- paths:
- pathPrefix: /pipeline
backend: pipeline-demo
`
err = applyResource(yamlStr)
assert.NoError(err)
time.Sleep(1 * time.Second)
cmd.Process.Kill()
assert.True(strings.Contains(stdout.String(), "test-egctl-logs"))
}
}
48 changes: 3 additions & 45 deletions cmd/client/commandv2/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,13 @@
package commandv2

import (
"errors"

"github.com/megaease/easegress/v2/cmd/client/general"
"github.com/megaease/easegress/v2/cmd/client/resources"
"github.com/megaease/easegress/v2/cmd/client/commandv2/create"
"github.com/spf13/cobra"
)

// CreateCmd returns create command.
func CreateCmd() *cobra.Command {
examples := []general.Example{
{Desc: "Create a resource from a file", Command: "egctl create -f <filename>.yaml"},
{Desc: "Create a resource from stdin", Command: "cat <filename>.yaml | egctl create -f -"},
}

var specFile string
cmd := &cobra.Command{
Use: "create",
Short: "Create a resource from a file or from stdin.",
Example: createMultiExample(examples),
Args: func(cmd *cobra.Command, args []string) error {
if specFile == "" {
return errors.New("yaml file is required")
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
visitor := general.BuildSpecVisitor(specFile, cmd)
visitor.Visit(func(s *general.Spec) error {
var err error
defer func() {
if err != nil {
general.ExitWithError(err)
}
}()

switch s.Kind {
case resources.CustomDataKind().Kind:
err = resources.CreateCustomDataKind(cmd, s)
case resources.CustomData().Kind:
err = resources.CreateCustomData(cmd, s)
default:
err = resources.CreateObject(cmd, s)
}
return err
})
visitor.Close()
},
}

cmd.Flags().StringVarP(&specFile, "file", "f", "", "A yaml file specifying the object.")
cmd := create.Cmd()
cmd.AddCommand(create.HTTPProxyCmd())
return cmd
}
73 changes: 73 additions & 0 deletions cmd/client/commandv2/create/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2017, MegaEase
* All rights reserved.
*
* Licensed 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:https://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 create provides create commands.
package create

import (
"errors"

"github.com/megaease/easegress/v2/cmd/client/general"
"github.com/megaease/easegress/v2/cmd/client/resources"
"github.com/spf13/cobra"
)

// Cmd returns create command.
func Cmd() *cobra.Command {
examples := []general.Example{
{Desc: "Create a resource from a file", Command: "egctl create -f <filename>.yaml"},
{Desc: "Create a resource from stdin", Command: "cat <filename>.yaml | egctl create -f -"},
}

var specFile string
cmd := &cobra.Command{
Use: "create",
Short: "Create a resource from a file or from stdin.",
Example: general.CreateMultiExample(examples),
Args: func(cmd *cobra.Command, args []string) error {
if specFile == "" {
return errors.New("yaml file is required")
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
visitor := general.BuildSpecVisitor(specFile, cmd)
visitor.Visit(func(s *general.Spec) error {
var err error
defer func() {
if err != nil {
general.ExitWithError(err)
}
}()

switch s.Kind {
case resources.CustomDataKind().Kind:
err = resources.CreateCustomDataKind(cmd, s)
case resources.CustomData().Kind:
err = resources.CreateCustomData(cmd, s)
default:
err = resources.CreateObject(cmd, s)
}
return err
})
visitor.Close()
},
}

cmd.Flags().StringVarP(&specFile, "file", "f", "", "A yaml file specifying the object.")
return cmd
}
30 changes: 30 additions & 0 deletions cmd/client/commandv2/create/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2017, MegaEase
* All rights reserved.
*
* Licensed 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:https://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 create provides create commands.
package create

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestCmd(t *testing.T) {
cmd := Cmd()
assert.NotNil(t, cmd)
}
Loading
Loading