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

feat(kumactl): inspect api support #3805

Merged
merged 3 commits into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
444 changes: 444 additions & 0 deletions app/kumactl/cmd/completion/testdata/bash.golden

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions app/kumactl/cmd/inspect/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
"github.com/kumahq/kuma/app/kumactl/pkg/output"
kuma_cmd "github.com/kumahq/kuma/pkg/cmd"
core_model "github.com/kumahq/kuma/pkg/core/resources/model"
"github.com/kumahq/kuma/pkg/core/resources/registry"
)

func NewInspectCmd(pctx *kumactl_cmd.RootContext) *cobra.Command {
Expand All @@ -27,10 +29,16 @@ func NewInspectCmd(pctx *kumactl_cmd.RootContext) *cobra.Command {
inspectCmd.PersistentFlags().StringVarP(&pctx.InspectContext.Args.OutputFormat, "output", "o", string(output.TableFormat), kuma_cmd.UsageOptions("output format", output.TableFormat, output.YAMLFormat, output.JSONFormat))
// sub-commands
inspectCmd.AddCommand(newInspectDataplanesCmd(pctx))
inspectCmd.AddCommand(newInspectDataplaneCmd(pctx))
inspectCmd.AddCommand(newInspectZoneIngressesCmd(pctx))
inspectCmd.AddCommand(newInspectZoneIngressCmd(pctx))
inspectCmd.AddCommand(newInspectZoneEgressesCmd(pctx))
inspectCmd.AddCommand(newInspectZonesCmd(pctx))
inspectCmd.AddCommand(newInspectMeshesCmd(pctx))
inspectCmd.AddCommand(newInspectServicesCmd(pctx))

for _, desc := range registry.Global().ObjectDescriptors(core_model.AllowedToInspect()) {
inspectCmd.AddCommand(newInspectPolicyCmd(desc, pctx))
}
return inspectCmd
}
60 changes: 60 additions & 0 deletions app/kumactl/cmd/inspect/inspect_dataplane.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package inspect

import (
"context"
"fmt"
"text/template"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/kumahq/kuma/app/kumactl/pkg/cmd"
)

var dataplaneInspectTemplate = "{{ range .Items }}" +
"{{ .AttachmentEntry | FormatAttachment }}:\n" +
"{{ range $typ, $policies := .MatchedPolicies }}" +
" {{ $typ }}\n" +
" {{ range $policies }}{{ .Meta.Name }}\n{{ end }}" +
"{{ end }}" +
"\n" +
"{{ end }}"

func newInspectDataplaneCmd(pctx *cmd.RootContext) *cobra.Command {
tmpl, err := template.New("dataplane_inspect").Funcs(template.FuncMap{
"FormatAttachment": attachmentToStr(true),
}).Parse(dataplaneInspectTemplate)
if err != nil {
panic("unable to parse template")
}
var configDump bool
cmd := &cobra.Command{
Use: "dataplane NAME",
Short: "Inspect Dataplane",
Long: "Inspect Dataplane.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := pctx.CurrentDataplaneInspectClient()
if err != nil {
return errors.Wrap(err, "failed to create a dataplane inspect client")
}
name := args[0]
if configDump {
bytes, err := client.InspectConfigDump(context.Background(), pctx.CurrentMesh(), name)
if err != nil {
return err
}
_, err = fmt.Fprint(cmd.OutOrStdout(), string(bytes))
return err
} else {
entryList, err := client.InspectPolicies(context.Background(), pctx.CurrentMesh(), name)
if err != nil {
return err
}
return tmpl.Execute(cmd.OutOrStdout(), entryList)
}
},
}
cmd.PersistentFlags().BoolVar(&configDump, "config-dump", false, "if set then the command returns envoy config dump for provided dataplane")
return cmd
}
94 changes: 94 additions & 0 deletions app/kumactl/cmd/inspect/inspect_dataplane_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package inspect_test

import (
"bytes"
"context"
"encoding/json"
"os"
"path"
"path/filepath"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
gomega_types "github.com/onsi/gomega/types"
"github.com/spf13/cobra"

"github.com/kumahq/kuma/app/kumactl/cmd"
"github.com/kumahq/kuma/app/kumactl/pkg/resources"
api_server_types "github.com/kumahq/kuma/pkg/api-server/types"
"github.com/kumahq/kuma/pkg/core/resources/registry"
test_kumactl "github.com/kumahq/kuma/pkg/test/kumactl"
"github.com/kumahq/kuma/pkg/test/matchers"
util_http "github.com/kumahq/kuma/pkg/util/http"
)

type testDataplaneInspectClient struct {
response *api_server_types.DataplaneInspectEntryList
}

func (t *testDataplaneInspectClient) InspectPolicies(ctx context.Context, mesh, name string) (*api_server_types.DataplaneInspectEntryList, error) {
return t.response, nil
}

func (t *testDataplaneInspectClient) InspectConfigDump(ctx context.Context, mesh, name string) ([]byte, error) {
return nil, nil
}

var _ resources.DataplaneInspectClient = &testDataplaneInspectClient{}

var _ = Describe("kumactl inspect dataplane", func() {

var rootCmd *cobra.Command
var buf *bytes.Buffer

BeforeEach(func() {
rawResponse, err := os.ReadFile(path.Join("testdata", "inspect-dataplane.server-response.json"))
Expect(err).ToNot(HaveOccurred())

receiver := &api_server_types.DataplaneInspectEntryListReceiver{
NewResource: registry.Global().NewObject,
}
Expect(json.Unmarshal(rawResponse, receiver)).To(Succeed())

testClient := &testDataplaneInspectClient{
response: &receiver.DataplaneInspectEntryList,
}

rootCtx, err := test_kumactl.MakeRootContext(time.Now(), nil)
Expect(err).ToNot(HaveOccurred())

rootCtx.Runtime.NewDataplaneInspectClient = func(client util_http.Client) resources.DataplaneInspectClient {
return testClient
}

rootCmd = cmd.NewRootCmd(rootCtx)
buf = &bytes.Buffer{}
rootCmd.SetOut(buf)
})

type testCase struct {
goldenFile string
matcher func(path ...string) gomega_types.GomegaMatcher
}
DescribeTable("kumactl inspect dataplane",
func(given testCase) {
// given
rootCmd.SetArgs([]string{
"--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"),
"inspect", "dataplane", "backend-1"})

// when
err := rootCmd.Execute()

// then
Expect(err).ToNot(HaveOccurred())
Expect(buf.String()).To(given.matcher("testdata", given.goldenFile))
},
Entry("default output", testCase{
goldenFile: "inspect-dataplane.golden.txt",
matcher: matchers.MatchGoldenEqual,
}),
)
})
81 changes: 81 additions & 0 deletions app/kumactl/cmd/inspect/inspect_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package inspect

import (
"context"
"fmt"
"strings"
"text/template"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/kumahq/kuma/app/kumactl/pkg/cmd"
api_server_types "github.com/kumahq/kuma/pkg/api-server/types"
core_model "github.com/kumahq/kuma/pkg/core/resources/model"
)

var policyInspectTemplate = "Affected data plane proxies:\n\n" +
"{{ range .Items }}" +
" {{ .DataplaneKey.Name }}" +
"{{ if . | PrintAttachments }}" +
":\n" +
"{{ range .Attachments }}" +
" {{ . | FormatAttachment }}\n" +
"{{ end }}" +
"{{ end }}" +
"\n" +
"{{ end }}"

func newInspectPolicyCmd(policyDesc core_model.ResourceTypeDescriptor, pctx *cmd.RootContext) *cobra.Command {
tmpl, err := template.New("policy_inspect").Funcs(template.FuncMap{
"FormatAttachment": attachmentToStr(false),
"PrintAttachments": func(e api_server_types.PolicyInspectEntry) bool {
if len(e.Attachments) == 1 && e.Attachments[0].Type == "dataplane" {
return false
}
return true
},
}).Parse(policyInspectTemplate)
if err != nil {
panic("unable to parse template")
}

cmd := &cobra.Command{
Use: fmt.Sprintf("%s NAME", policyDesc.KumactlArg),
Short: fmt.Sprintf("Inspect %s", policyDesc.Name),
Long: fmt.Sprintf("Inspect %s.", policyDesc.Name),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := pctx.CurrentPolicyInspectClient()
if err != nil {
return errors.Wrap(err, "failed to create a policy inspect client")
}
name := args[0]
entryList, err := client.Inspect(context.Background(), policyDesc, pctx.CurrentMesh(), name)
if err != nil {
return err
}
return tmpl.Execute(cmd.OutOrStdout(), entryList)
},
}
return cmd
}

func attachmentToStr(upperCase bool) func(api_server_types.AttachmentEntry) string {
return func(a api_server_types.AttachmentEntry) string {
typeToStr := func(t string) string {
if upperCase {
return strings.ToUpper(t)
}
return t
}
switch a.Type {
case "dataplane":
return typeToStr(a.Type)
case "service":
return fmt.Sprintf("%s %s", typeToStr(a.Type), a.Name)
default:
return fmt.Sprintf("%s %s(%s)", typeToStr(a.Type), a.Name, a.Service)
}
}
}
95 changes: 95 additions & 0 deletions app/kumactl/cmd/inspect/inspect_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package inspect_test

import (
"bytes"
"context"
"encoding/json"
"os"
"path"
"path/filepath"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"

"github.com/kumahq/kuma/app/kumactl/cmd"
"github.com/kumahq/kuma/app/kumactl/pkg/resources"
api_server_types "github.com/kumahq/kuma/pkg/api-server/types"
"github.com/kumahq/kuma/pkg/core/resources/model"
test_kumactl "github.com/kumahq/kuma/pkg/test/kumactl"
"github.com/kumahq/kuma/pkg/test/matchers"
util_http "github.com/kumahq/kuma/pkg/util/http"
)

type testPolicyInspectClient struct {
response *api_server_types.PolicyInspectEntryList
}

func (t *testPolicyInspectClient) Inspect(ctx context.Context, policyDesc model.ResourceTypeDescriptor, mesh, name string) (*api_server_types.PolicyInspectEntryList, error) {
return t.response, nil
}

var _ resources.PolicyInspectClient = &testPolicyInspectClient{}

var _ = Describe("kumactl inspect POLICY", func() {

type testCase struct {
goldenFile string
serverResponseFile string
cmdArgs []string
}
DescribeTable("kumactl inspect dataplane",
func(given testCase) {
// given
rawResponse, err := os.ReadFile(path.Join("testdata", given.serverResponseFile))
Expect(err).ToNot(HaveOccurred())

entryList := &api_server_types.PolicyInspectEntryList{}
Expect(json.Unmarshal(rawResponse, entryList)).To(Succeed())

rootCtx, err := test_kumactl.MakeRootContext(time.Now(), nil)
Expect(err).ToNot(HaveOccurred())

rootCtx.Runtime.NewPolicyInspectClient = func(client util_http.Client) resources.PolicyInspectClient {
return &testPolicyInspectClient{
response: entryList,
}
}

rootCmd := cmd.NewRootCmd(rootCtx)
buf := &bytes.Buffer{}
rootCmd.SetOut(buf)

rootCmd.SetArgs(append([]string{"--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml")},
given.cmdArgs...))

// when
err = rootCmd.Execute()

// then
Expect(err).ToNot(HaveOccurred())
Expect(buf.String()).To(matchers.MatchGoldenEqual("testdata", given.goldenFile))
},
Entry("inbound policy", testCase{
goldenFile: "inspect-traffic-permission.golden.txt",
serverResponseFile: "inspect-traffic-permission.server-response.json",
cmdArgs: []string{"inspect", "traffic-permission", "tp1"},
}),
Entry("outbound policy", testCase{
goldenFile: "inspect-timeout.golden.txt",
serverResponseFile: "inspect-timeout.server-response.json",
cmdArgs: []string{"inspect", "timeout", "t1"},
}),
Entry("service policy", testCase{
goldenFile: "inspect-health-check.golden.txt",
serverResponseFile: "inspect-health-check.server-response.json",
cmdArgs: []string{"inspect", "healthcheck", "hc1"},
}),
Entry("dataplane policy", testCase{
goldenFile: "inspect-traffic-trace.golden.txt",
serverResponseFile: "inspect-traffic-trace.server-response.json",
cmdArgs: []string{"inspect", "traffic-trace", "tt1"},
}),
)
})
Loading