-
Notifications
You must be signed in to change notification settings - Fork 24
feat(mesh): core command surface for Kong Mesh control planes #2128
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
base: main
Are you sure you want to change the base?
Changes from all commits
86fd505
f271dcf
13a155d
3d0c96d
88d9211
dcd7059
12fe535
66a5680
cc2458e
e4d2282
1c3e302
e4ebac5
b744b38
834c5ad
76761c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package root | ||
|
|
||
| import ( | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| // Mesh is reachable both directly and under the explicit product path. The | ||
| // constructors promise both, but only the direct form was registered, so | ||
| // `kongctl get konnect mesh` failed with "unknown command". These assert the | ||
| // real command paths rather than the constructors. | ||
| func TestMeshCommandPathsResolve(t *testing.T) { | ||
| // Every verb Kong Mesh serves here. `apply konnect` and `delete konnect` | ||
| // are replaced by the declarative commands and take their own arguments, | ||
| // so those two are served by the direct form only. | ||
| paths := [][]string{ | ||
| {"apply", "mesh", "--help"}, | ||
| {"get", "mesh", "--help"}, | ||
| {"get", "konnect", "mesh", "--help"}, | ||
| {"create", "mesh", "--help"}, | ||
| {"create", "konnect", "mesh", "--help"}, | ||
| {"delete", "mesh", "--help"}, | ||
| } | ||
|
|
||
| for _, args := range paths { | ||
| path := strings.Join(args[:len(args)-1], " ") | ||
|
|
||
| t.Run(path, func(t *testing.T) { | ||
| result := executeRootForTest(t, args...) | ||
|
|
||
| if result.exitCode != 0 { | ||
| t.Fatalf("expected %q to succeed\nstdout:\n%s\nstderr:\n%s", | ||
| path, result.stdout, result.stderr) | ||
| } | ||
| if strings.Contains(result.stderr, "unknown command") { | ||
| t.Fatalf("expected %q to be registered\nstderr:\n%s", path, result.stderr) | ||
| } | ||
| // The mesh command's own help, not a parent's help that merely | ||
| // lists it: a swallowed argument prints the parent's help and | ||
| // still exits zero. | ||
| if !strings.Contains(result.stdout, "Kong Mesh control plane") { | ||
| t.Fatalf("expected %q help to describe the mesh command\nstdout:\n%s", | ||
| path, result.stdout) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ package konnect | |
| import ( | ||
| "context" | ||
| "fmt" | ||
| "slices" | ||
|
|
||
| cmdpkg "github.com/kong/kongctl/internal/cmd" | ||
| commoncmd "github.com/kong/kongctl/internal/cmd/common" | ||
|
|
@@ -19,6 +20,7 @@ import ( | |
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/eventgateway" | ||
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/gateway" | ||
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/me" | ||
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/mesh" | ||
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/organization" | ||
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/portal" | ||
| "github.com/kong/kongctl/internal/cmd/root/products/konnect/regions" | ||
|
|
@@ -201,6 +203,39 @@ func preRunE(c *cobra.Command, args []string) error { | |
| return bindFlags(c, args) | ||
| } | ||
|
|
||
| // meshVerbs are the verbs Kong Mesh serves under the explicit product path. | ||
| var meshVerbs = []verbs.VerbValue{verbs.Get, verbs.Create, verbs.Dump} | ||
|
|
||
| // addMeshCommand registers Kong Mesh under the explicit product path, giving | ||
| // `kongctl <verb> konnect mesh ...` alongside the direct `kongctl <verb> mesh | ||
| // ...` form that the root command registers. | ||
| // | ||
| // Mesh serves a subset of the verbs, so an unsupported verb registers nothing | ||
| // rather than adding a command that cannot run. | ||
| // | ||
| // Apply and delete are absent deliberately. `apply konnect` and `delete | ||
| // konnect` are replaced by the declarative commands, which take their own | ||
| // arguments, so a `mesh` subcommand there is read as one of them instead of | ||
| // dispatching. Both are served by the direct `apply mesh` and `delete mesh` | ||
| // forms. | ||
| func addMeshCommand( | ||
| cmd *cobra.Command, | ||
| verb verbs.VerbValue, | ||
| addParentFlags func(verbs.VerbValue, *cobra.Command), | ||
| parentPreRun func(*cobra.Command, []string) error, | ||
| ) error { | ||
| if !slices.Contains(meshVerbs, verb) { | ||
| return nil | ||
| } | ||
|
|
||
| meshCmd, err := mesh.NewMeshCmd(verb, addParentFlags, parentPreRun) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Medium: bind Mesh flags on the explicit Konnect command path. This passes the general Konnect pre-run handler, which does not call Reproduced: Compose the Konnect and Mesh bindings for this path, including token subcommands. Test actual requests through both direct and explicit command trees, verifying that selectors and command-specific settings take effect. |
||
| if err != nil { | ||
| return err | ||
| } | ||
| cmd.AddCommand(meshCmd) | ||
| return nil | ||
| } | ||
|
|
||
| func NewKonnectCmd(verb verbs.VerbValue) (*cobra.Command, error) { | ||
| cmd := &cobra.Command{ | ||
| Use: konnectUse, | ||
|
|
@@ -234,6 +269,9 @@ func NewKonnectCmd(verb verbs.VerbValue) (*cobra.Command, error) { | |
| if err := addTokenCommands(cmd, verb, addFlags, preRunE); err != nil { | ||
| return nil, err | ||
| } | ||
| if err := addMeshCommand(cmd, verb, addFlags, preRunE); err != nil { | ||
| return nil, err | ||
| } | ||
| addFlags(verb, cmd) | ||
| return cmd, nil | ||
| } | ||
|
|
@@ -420,6 +458,10 @@ func NewKonnectCmd(verb verbs.VerbValue) (*cobra.Command, error) { | |
| } | ||
| cmd.AddCommand(egcpc) | ||
|
|
||
| if err := addMeshCommand(cmd, verb, addFlags, preRunE); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if verb == verbs.Get { | ||
| cmd.RunE = func(c *cobra.Command, args []string) error { | ||
| helper := cmdpkg.BuildHelper(c, args) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add request-level command tests and dedicated Mesh E2E scenarios.
The additional tests are useful, but these command-path tests execute only
--help, which bypasses the bindings and requests that currently fail on the explicit Konnect path. Selector tests exercise flag detection rather than the combined URL/authentication decision.TestMeshOptionPrecedencealso claims environment coverage but contains no environment-variable case.Add complete command/HTTP tests for direct and explicit paths, selector/authentication combinations, file/environment/flag precedence, pagination, TLS credential isolation, and write behavior. Add isolated Mesh discovery/read, apply/get/delete, and token E2E scenarios with cleanup, and run them through trusted E2E. There are still no Mesh scenarios in this PR; passing smoke/version does not validate the feature.