From 9eb4601363e4697f5097d983195feeb9e59e58ba Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 13:58:58 +0100 Subject: [PATCH 1/5] =?UTF-8?q?topology=20command:=20open=20svg=20graph=20?= =?UTF-8?q?in=20the=20user=E2=80=99s=20preferred=20application?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eguzki Astiz Lezaun --- cmd/topology.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cmd/topology.go b/cmd/topology.go index a9ce689..d68c6b8 100644 --- a/cmd/topology.go +++ b/cmd/topology.go @@ -2,8 +2,11 @@ package cmd import ( "bytes" + "errors" "fmt" "os" + "os/exec" + "strings" "github.com/goccy/go-graphviz" "github.com/spf13/cobra" @@ -37,6 +40,9 @@ func topologyCommand() *cobra.Command { } func runTopology(cmd *cobra.Command, args []string) error { + if !strings.HasSuffix(topologyOutputFile, ".svg") { + return errors.New("output file must have .svg extension") + } ctx := cmd.Context() configuration, err := config.GetConfig() if err != nil { @@ -108,5 +114,16 @@ func runTopology(cmd *cobra.Command, args []string) error { return err } + openCmd := exec.Command("open", topologyOutputFile) + // pipe the commands output to the applications + // standard output + openCmd.Stdout = os.Stdout + + // Run still runs the command and waits for completion + // but the output is instantly piped to Stdout + if err := openCmd.Run(); err != nil { + return err + } + return nil } From fbc068bba77cc2adef71bdd60aa5780e7c93ef5e Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 14:09:01 +0100 Subject: [PATCH 2/5] topology command: cosmetic changes Signed-off-by: Eguzki Astiz Lezaun --- cmd/topology.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/topology.go b/cmd/topology.go index d68c6b8..2c3cd0a 100644 --- a/cmd/topology.go +++ b/cmd/topology.go @@ -25,13 +25,13 @@ var ( func topologyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "topology", - Short: "Read kuadrant topology", - Long: "Read kuadrant topology", + Short: "Export and visualize kuadrant topology", + Long: "Export and visualize kuadrant topology", RunE: runTopology, } cmd.Flags().StringVarP(&topologyNS, "namespace", "n", "kuadrant-system", "Topology's namespace") - cmd.Flags().StringVarP(&topologyOutputFile, "output", "o", "(required)", "Output file") + cmd.Flags().StringVarP(&topologyOutputFile, "output", "o", "", "Output file") err := cmd.MarkFlagRequired("output") if err != nil { panic(err) From 5ec937223ec1600e6fbdd3be2f254aa2860f9f70 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 17:20:22 +0100 Subject: [PATCH 3/5] topology command: --dot optional flag for DOT file Signed-off-by: Eguzki Astiz Lezaun --- cmd/topology.go | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/cmd/topology.go b/cmd/topology.go index 2c3cd0a..3793ced 100644 --- a/cmd/topology.go +++ b/cmd/topology.go @@ -3,7 +3,6 @@ package cmd import ( "bytes" "errors" - "fmt" "os" "os/exec" "strings" @@ -18,8 +17,9 @@ import ( ) var ( - topologyNS string - topologyOutputFile string + topologyNS string + topologySVGOutputFile string + topologyDOTOutputFile string ) func topologyCommand() *cobra.Command { @@ -31,7 +31,8 @@ func topologyCommand() *cobra.Command { } cmd.Flags().StringVarP(&topologyNS, "namespace", "n", "kuadrant-system", "Topology's namespace") - cmd.Flags().StringVarP(&topologyOutputFile, "output", "o", "", "Output file") + cmd.Flags().StringVarP(&topologySVGOutputFile, "output", "o", "", "SVG image output file") + cmd.Flags().StringVarP(&topologyDOTOutputFile, "dot", "d", "", "Graphviz DOT output file") err := cmd.MarkFlagRequired("output") if err != nil { panic(err) @@ -40,7 +41,7 @@ func topologyCommand() *cobra.Command { } func runTopology(cmd *cobra.Command, args []string) error { - if !strings.HasSuffix(topologyOutputFile, ".svg") { + if !strings.HasSuffix(topologySVGOutputFile, ".svg") { return errors.New("output file must have .svg extension") } ctx := cmd.Context() @@ -62,18 +63,18 @@ func runTopology(cmd *cobra.Command, args []string) error { return err } - topologyOutputFileInDotFormat := fmt.Sprintf("%s.dot", topologyOutputFile) - - fDot, err := os.Create(topologyOutputFileInDotFormat) - if err != nil { - return err - } - defer fDot.Close() - - _, err = fDot.WriteString(topologyConfigMap.Data["topology"]) - logf.Log.V(1).Info("write topology in DOT format to file", "file", topologyOutputFileInDotFormat, "error", err) - if err != nil { - return err + if topologyDOTOutputFile != "" { + fDot, err := os.Create(topologyDOTOutputFile) + if err != nil { + return err + } + defer fDot.Close() + + _, err = fDot.WriteString(topologyConfigMap.Data["topology"]) + logf.Log.V(1).Info("write topology in DOT format to file", "file", topologyDOTOutputFile, "error", err) + if err != nil { + return err + } } g, err := graphviz.New(ctx) @@ -102,19 +103,19 @@ func runTopology(cmd *cobra.Command, args []string) error { } // write to file - fSvg, err := os.Create(topologyOutputFile) + fSvg, err := os.Create(topologySVGOutputFile) if err != nil { return err } defer fSvg.Close() _, err = fSvg.Write(buf.Bytes()) - logf.Log.V(1).Info("write topology in SVG format to file", "file", topologyOutputFile, "error", err) + logf.Log.V(1).Info("write topology in SVG format to file", "file", topologySVGOutputFile, "error", err) if err != nil { return err } - openCmd := exec.Command("open", topologyOutputFile) + openCmd := exec.Command("open", topologySVGOutputFile) // pipe the commands output to the applications // standard output openCmd.Stdout = os.Stdout From 5dfb0d6022038113d851e0bf9fcdfb194faccace Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 17:24:00 +0100 Subject: [PATCH 4/5] topology command: external command xdg-open|open Signed-off-by: Eguzki Astiz Lezaun --- cmd/topology.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/topology.go b/cmd/topology.go index 3793ced..0cec6d4 100644 --- a/cmd/topology.go +++ b/cmd/topology.go @@ -115,7 +115,12 @@ func runTopology(cmd *cobra.Command, args []string) error { return err } - openCmd := exec.Command("open", topologySVGOutputFile) + externalCommand := "xdg-open" + if _, err := exec.LookPath("open"); err == nil { + externalCommand = "open" + } + + openCmd := exec.Command(externalCommand, topologySVGOutputFile) // pipe the commands output to the applications // standard output openCmd.Stdout = os.Stdout From fc0618500309b8ae0f4c63c3fe3a2d0b62c4a568 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 17:27:23 +0100 Subject: [PATCH 5/5] topology command: doc Signed-off-by: Eguzki Astiz Lezaun --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5aace09..ed9c52f 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,9 @@ kuadrantctl [command] [subcommand] [flags] | ------------ | ---------------------------------------------------------- | | `completion` | Generate autocompletion scripts for the specified shell | | `generate` | Commands related to Kubernetes Gateway API and Kuadrant resource generation from OpenAPI 3.x specifications | +| `topology` | Command related to Kuadrant topology | | `help` | Help about any command | -| `version` | Print the version number of `kuadrantctl` | +| `version` | Print the version number of `kuadrantctl` | ### Flags @@ -81,6 +82,29 @@ Generate Gateway API resources from an OpenAPI 3.x specification | ---------- | ------------------------------------------------ | --------------------------------- | | `httproute`| Generate Gateway API HTTPRoute from OpenAPI 3.0.X| `--oas string` Path to OpenAPI spec file (in JSON or YAML format), URL, or '-' to read from standard input (required). `-o` Output format: 'yaml' or 'json'. (default "yaml") | +#### `topology` + +Export and visualize kuadrant topology + +### Usage + +```shell +$ kuadrantctl topology -h +Export and visualize kuadrant topology + +Usage: + kuadrantctl topology [flags] + +Flags: + -d, --dot string Graphviz DOT output file + -h, --help help for topology + -n, --namespace string Topology's namespace (default "kuadrant-system") + -o, --output string SVG image output file + +Global Flags: + -v, --verbose verbose output +``` + ##### `generate kuadrant` Generate Kuadrant resources from an OpenAPI 3.x specification