Skip to content

Commit

Permalink
support egctl get describe different namespace (#1197)
Browse files Browse the repository at this point in the history
* support egctl get to display httpserver and pipelines in different namespace

* egctl describe cmd support multi namespace, fix previous bugs when query status of non-traffic object

* add integration tests

* Update pkg/api/cluster.go

Co-authored-by: Yun Long <[email protected]>

* Update pkg/api/object.go

Co-authored-by: Yun Long <[email protected]>

* Update pkg/api/object.go

Co-authored-by: Yun Long <[email protected]>

* Update pkg/object/trafficcontroller/trafficcontroller.go

Co-authored-by: Yun Long <[email protected]>

* update based on comments

---------

Co-authored-by: Yun Long <[email protected]>
  • Loading branch information
suchen-sci and xxx7xxxx committed Jan 26, 2024
1 parent 6906af7 commit 25e4240
Show file tree
Hide file tree
Showing 13 changed files with 839 additions and 67 deletions.
226 changes: 226 additions & 0 deletions build/test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@ func TestCreateHTTPProxy(t *testing.T) {
assert.Empty(stderr)
defer func() {
deleteResource("httpserver", "http-proxy-test")
deleteResource("pipeline", "--all")
}()

output, err := getResource("httpserver")
Expand Down Expand Up @@ -1312,3 +1313,228 @@ filters:
// get this body means our pipeline is working.
assert.Equal("body from response builder", string(data))
}

func TestEgctlNamespace(t *testing.T) {
assert := assert.New(t)
mockNamespace := `
name: mockNamespace
kind: MockNamespacer
namespace: mockNamespace
httpservers:
- kind: HTTPServer
name: mock-httpserver
port: 10222
https: false
rules:
- paths:
- path: /pipeline
backend: mock-pipeline
pipelines:
- name: mock-pipeline
kind: Pipeline
flow:
- filter: proxy
filters:
- name: proxy
kind: Proxy
pools:
- servers:
- url: http:https://127.0.0.1:9095
- url: http:https://127.0.0.1:9096
loadBalance:
policy: roundRobin
`
err := createResource(mockNamespace)
assert.Nil(err)
defer func() {
err := deleteResource("MockNamespacer", "mockNamespace")
assert.Nil(err)
}()

httpserver := `
name: httpserver-test
kind: HTTPServer
port: 10181
https: false
keepAlive: true
keepAliveTimeout: 75s
maxConnection: 10240
cacheSize: 0
rules:
- paths:
- backend: pipeline-test
`
err = createResource(httpserver)
assert.Nil(err)
defer func() {
err := deleteResource("HTTPServer", "httpserver-test")
assert.Nil(err)
}()

pipeline := `
name: pipeline-test
kind: Pipeline
flow:
- filter: proxy
filters:
- name: proxy
kind: Proxy
pools:
- servers:
- url: http:https://127.0.0.1:8888
`
err = createResource(pipeline)
assert.Nil(err)
defer func() {
err := deleteResource("Pipeline", "pipeline-test")
assert.Nil(err)
}()

// egctl get all
{
// by default, list resources in "default" namespace
cmd := egctlCmd("get", "all")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.Contains(output, "httpserver-test")
assert.Contains(output, "pipeline-test")
assert.NotContains(output, "mock-httpserver")
assert.NotContains(output, "mock-pipeline")
}

// egctl get all --all-namespaces
{
cmd := egctlCmd("get", "all", "--all-namespaces")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.Contains(output, "httpserver-test")
assert.Contains(output, "pipeline-test")
assert.Contains(output, "mock-httpserver")
assert.Contains(output, "mock-pipeline")
}

// egctl get all --namespace mockNamespace
{
cmd := egctlCmd("get", "all", "--namespace", "mockNamespace")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.NotContains(output, "httpserver-test")
assert.NotContains(output, "pipeline-test")
assert.Contains(output, "mock-httpserver")
assert.Contains(output, "mock-pipeline")
}

// egctl get all --namespace default
{
cmd := egctlCmd("get", "all", "--namespace", "default")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.Contains(output, "httpserver-test")
assert.Contains(output, "pipeline-test")
assert.NotContains(output, "mock-httpserver")
assert.NotContains(output, "mock-pipeline")
}

// egctl get hs --namespace mockNamespace
{
cmd := egctlCmd("get", "hs", "--namespace", "mockNamespace")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.NotContains(output, "httpserver-test")
assert.NotContains(output, "pipeline-test")
assert.Contains(output, "mock-httpserver")
assert.NotContains(output, "mock-pipeline")
}

// egctl get hs --all-namespaces
{
cmd := egctlCmd("get", "hs", "--all-namespaces")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.Contains(output, "httpserver-test")
assert.NotContains(output, "pipeline-test")
assert.Contains(output, "mock-httpserver")
assert.NotContains(output, "mock-pipeline")
}

// egctl get hs mock-httpserver --namespace mockNamespace -o yaml
{
cmd := egctlCmd("get", "hs", "mock-httpserver", "--namespace", "mockNamespace", "-o", "yaml")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.NotContains(output, "httpserver-test")
assert.NotContains(output, "pipeline-test")
assert.Contains(output, "mock-httpserver")
assert.Contains(output, "port: 10222")
}

// easegress update status every 5 seconds
time.Sleep(5 * time.Second)

// egctl describe httpserver --all-namespaces
{
cmd := egctlCmd("describe", "httpserver", "--all-namespaces")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.Contains(output, "Name: httpserver-test")
assert.Contains(output, "Name: mock-httpserver")
assert.NotContains(output, "Name: pipeline-test")
assert.NotContains(output, "Name: mock-pipeline")
assert.Contains(output, "In Namespace default")
assert.Contains(output, "In Namespace mockNamespace")
// check if status is updated
assert.Equal(2, strings.Count(output, "node: primary-single"))
assert.Equal(2, strings.Count(output, "m1ErrPercent: 0"))
}

// egctl describe httpserver --namespace mockNamespace
{
cmd := egctlCmd("describe", "httpserver", "--namespace", "mockNamespace")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.Contains(output, "Name: mock-httpserver")
assert.NotContains(output, "Name: httpserver-test")
assert.NotContains(output, "Name: pipeline-test")
assert.NotContains(output, "Name: mock-pipeline")
// check if status is updated
assert.Equal(1, strings.Count(output, "node: primary-single"))
assert.Equal(1, strings.Count(output, "m1ErrPercent: 0"))
}

// egctl describe pipeline --namespace default
{
cmd := egctlCmd("describe", "pipeline", "--namespace", "default")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.NotContains(output, "Name: httpserver-test")
assert.Contains(output, "Name: pipeline-test")
assert.NotContains(output, "Name: mock-httpserver")
assert.NotContains(output, "Name: mock-pipeline")
// check if status is updated
assert.Equal(1, strings.Count(output, "node: primary-single"))
assert.Equal(1, strings.Count(output, "p999: 0"))
}

// egctl describe hs mock-httpserver --namespace mockNamespace -o yaml
{
cmd := egctlCmd("describe", "hs", "mock-httpserver", "--namespace", "mockNamespace", "-o", "yaml")
output, stderr, err := runCmd(cmd)
assert.Nil(err)
assert.Empty(stderr)
assert.NotContains(output, "httpserver-test")
assert.NotContains(output, "pipeline-test")
assert.Contains(output, "name: mock-httpserver")
assert.Contains(output, "port: 10222")
assert.Contains(output, "node: primary-single")
}
}
11 changes: 10 additions & 1 deletion cmd/client/commandv2/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"github.com/spf13/cobra"
)

var describeFlags resources.ObjectNamespaceFlags

// DescribeCmd returns describe command.
func DescribeCmd() *cobra.Command {
examples := []general.Example{
Expand All @@ -37,6 +39,8 @@ func DescribeCmd() *cobra.Command {
{Desc: "Describe all members", Command: "egctl describe member"},
{Desc: "Describe a customdata kind", Command: "egctl describe customdatakind <name>"},
{Desc: "Describe a customdata of given kind", Command: "egctl describe customdata <kind> <name>"},
{Desc: "Describe pipeline resources from all namespaces, including httpservers and pipelines created by IngressController, MeshController and GatewayController", Command: "egctl describe pipeline --all-namespaces"},
{Desc: "Describe httpserver resources from a certain namespace", Command: "egctl describe httpserver --namespace <namespace>"},
{Desc: "Check all possible api resources", Command: "egctl api-resources"},
}
cmd := &cobra.Command{
Expand All @@ -47,6 +51,11 @@ func DescribeCmd() *cobra.Command {
Run: describeCmdRun,
}
cmd.Flags().BoolVarP(&general.CmdGlobalFlags.Verbose, "verbose", "v", false, "Print verbose information")
cmd.Flags().StringVar(&describeFlags.Namespace, "namespace", "",
"namespace is used to describe httpservers and pipelines created by IngressController, MeshController or GatewayController"+
"(these objects create httpservers and pipelines in an independent namespace)")
cmd.Flags().BoolVar(&describeFlags.AllNamespace, "all-namespaces", false,
"describe all resources in all namespaces (including the ones created by IngressController, MeshController and GatewayController that are in an independent namespace)")
return cmd
}

Expand All @@ -71,7 +80,7 @@ func describeCmdRun(cmd *cobra.Command, args []string) {
case resources.Member().Kind:
err = resources.DescribeMember(cmd, a)
default:
err = resources.DescribeObject(cmd, a, kind)
err = resources.DescribeObject(cmd, a, kind, &describeFlags)
}
}

Expand Down
18 changes: 16 additions & 2 deletions cmd/client/commandv2/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (
"github.com/spf13/cobra"
)

var getFlags resources.ObjectNamespaceFlags

// GetCmd returns get command.
func GetCmd() *cobra.Command {
examples := []general.Example{
Expand All @@ -41,6 +43,8 @@ func GetCmd() *cobra.Command {
{Desc: "Get a customdata kind", Command: "egctl get customdatakind <name>"},
{Desc: "Get a customdata of given kind", Command: "egctl get customdata <kind> <name>"},
{Desc: "Check all possible api resources", Command: "egctl api-resources"},
{Desc: "Check all possible api resources from all namespaces, including httpservers and pipelines created by IngressController, MeshController and GatewayController", Command: "egctl get all --all-namespaces"},
{Desc: "Check all possible api resources from certain namespace", Command: "egctl get all --namespace <namespace>"},
}
cmd := &cobra.Command{
Use: "get",
Expand All @@ -49,6 +53,11 @@ func GetCmd() *cobra.Command {
Example: createMultiExample(examples),
Run: getCmdRun,
}
cmd.Flags().StringVar(&getFlags.Namespace, "namespace", "",
"namespace is used to get httpservers and pipelines created by IngressController, MeshController or GatewayController"+
"(these objects create httpservers and pipelines in an independent namespace)")
cmd.Flags().BoolVar(&getFlags.AllNamespace, "all-namespaces", false,
"get all resources in all namespaces (including the ones created by IngressController, MeshController and GatewayController that are in an independent namespace)")
return cmd
}

Expand All @@ -59,13 +68,18 @@ func getAllResources(cmd *cobra.Command) error {
errs = append(errs, err.Error())
}
}
err := resources.GetAllObject(cmd)
err := resources.GetAllObject(cmd, &getFlags)
if err != nil {
appendErr(err)
} else {
fmt.Printf("\n")
}

// non-default namespace is not supported for members and custom data kinds.
if getFlags.Namespace != "" && getFlags.Namespace != resources.DefaultNamespace {
return nil
}

funcs := []func(*cobra.Command, *general.ArgInfo) error{
resources.GetMember, resources.GetCustomDataKind,
}
Expand Down Expand Up @@ -109,7 +123,7 @@ func getCmdRun(cmd *cobra.Command, args []string) {
case resources.Member().Kind:
err = resources.GetMember(cmd, a)
default:
err = resources.GetObject(cmd, a, kind)
err = resources.GetObject(cmd, a, kind, &getFlags)
}
}

Expand Down
Loading

0 comments on commit 25e4240

Please sign in to comment.