From 07b486658079195887d20865fec799b6201df285 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Wed, 18 Dec 2024 23:33:01 +0100 Subject: [PATCH 1/7] topology command: persist in local disk Signed-off-by: Eguzki Astiz Lezaun --- cmd/root.go | 11 +++++--- cmd/topology.go | 64 +++++++++++++++++++++++++++++++++++++++++++++ cmd/version.go | 6 ----- pkg/utils/scheme.go | 27 ------------------- 4 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 cmd/topology.go delete mode 100644 pkg/utils/scheme.go diff --git a/cmd/root.go b/cmd/root.go index 6822ecc..c2dd710 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,6 +16,9 @@ limitations under the License. package cmd import ( + "context" + "os" + "github.com/spf13/cobra" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -32,6 +35,10 @@ func GetRootCmd(args []string) *cobra.Command { Use: "kuadrantctl", Short: "Kuadrant configuration command line utility", Long: "Kuadrant configuration command line utility", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + logf.SetLogger(zap.New(zap.UseDevMode(verbose), zap.WriteTo(os.Stdout))) + cmd.SetContext(context.Background()) + }, } rootCmd.SetArgs(args) @@ -42,9 +49,7 @@ func GetRootCmd(args []string) *cobra.Command { rootCmd.AddCommand(versionCommand()) rootCmd.AddCommand(generateCommand()) - - loggerOpts := zap.Options{Development: verbose} - logf.SetLogger(zap.New(zap.UseFlagOptions(&loggerOpts))) + rootCmd.AddCommand(topologyCommand()) return rootCmd } diff --git a/cmd/topology.go b/cmd/topology.go new file mode 100644 index 0000000..192f9aa --- /dev/null +++ b/cmd/topology.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" + logf "sigs.k8s.io/controller-runtime/pkg/log" +) + +var ( + topologyNS string + topologyOutputFile string +) + +func topologyCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "topology", + Short: "Read kuadrant topology", + Long: "Read kuadrant topology", + RunE: runTopology, + } + + cmd.Flags().StringVarP(&topologyNS, "namespace", "n", "kuadrant-system", "Topology's namespace") + cmd.Flags().StringVarP(&topologyOutputFile, "output", "o", "/dev/stdout", "Output file") + return cmd +} + +func runTopology(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + configuration, err := config.GetConfig() + if err != nil { + return err + } + + k8sClient, err := client.New(configuration, client.Options{Scheme: scheme.Scheme}) + if err != nil { + return err + } + + topologyKey := client.ObjectKey{Name: "topology", Namespace: topologyNS} + topologyConfigMap := &corev1.ConfigMap{} + err = k8sClient.Get(ctx, topologyKey, topologyConfigMap) + logf.Log.V(1).Info("reading topology", "object", client.ObjectKeyFromObject(topologyConfigMap), "error", err) + if err != nil { + return err + } + f, err := os.Create(topologyOutputFile) + logf.Log.V(1).Info("write topology topology to file", "file", topologyOutputFile, "error", err) + if err != nil { + return err + } + defer f.Close() + + _, err = f.WriteString(topologyConfigMap.Data["topology"]) + if err != nil { + return err + } + + return nil +} diff --git a/cmd/version.go b/cmd/version.go index 9390f08..71684e1 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -5,7 +5,6 @@ import ( "github.com/spf13/cobra" - "github.com/kuadrant/kuadrantctl/pkg/utils" "github.com/kuadrant/kuadrantctl/version" ) @@ -15,11 +14,6 @@ func versionCommand() *cobra.Command { Short: "Print the version number of kuadrantctl", Long: "Print the version number of kuadrantctl", RunE: func(cmd *cobra.Command, args []string) error { - err := utils.SetupScheme() - if err != nil { - return err - } - fmt.Printf("kuadrantctl %s (%s)\n", version.Version, version.GitHash) return nil }, diff --git a/pkg/utils/scheme.go b/pkg/utils/scheme.go deleted file mode 100644 index c500ac7..0000000 --- a/pkg/utils/scheme.go +++ /dev/null @@ -1,27 +0,0 @@ -package utils - -import ( - kuadrantoperator "github.com/kuadrant/kuadrant-operator/api/v1beta1" - operators "github.com/operator-framework/api/pkg/operators/v1alpha1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/client-go/kubernetes/scheme" -) - -func SetupScheme() error { - err := apiextensionsv1.AddToScheme(scheme.Scheme) - if err != nil { - return err - } - - err = operators.AddToScheme(scheme.Scheme) - if err != nil { - return err - } - - err = kuadrantoperator.AddToScheme(scheme.Scheme) - if err != nil { - return err - } - - return nil -} From fd21d07ea72a50e26751175c68ba40105d66b01f Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 10:57:09 +0100 Subject: [PATCH 2/7] topology command: additionally store in SVG format Signed-off-by: Eguzki Astiz Lezaun --- cmd/topology.go | 58 ++++++++++++++++++++++++++++++++++++++++++++----- go.mod | 31 +++++++++++++++----------- go.sum | 48 ++++++++++++++++++++++++---------------- 3 files changed, 100 insertions(+), 37 deletions(-) diff --git a/cmd/topology.go b/cmd/topology.go index 192f9aa..a9ce689 100644 --- a/cmd/topology.go +++ b/cmd/topology.go @@ -1,8 +1,11 @@ package cmd import ( + "bytes" + "fmt" "os" + "github.com/goccy/go-graphviz" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes/scheme" @@ -25,7 +28,11 @@ func topologyCommand() *cobra.Command { } cmd.Flags().StringVarP(&topologyNS, "namespace", "n", "kuadrant-system", "Topology's namespace") - cmd.Flags().StringVarP(&topologyOutputFile, "output", "o", "/dev/stdout", "Output file") + cmd.Flags().StringVarP(&topologyOutputFile, "output", "o", "(required)", "Output file") + err := cmd.MarkFlagRequired("output") + if err != nil { + panic(err) + } return cmd } @@ -48,14 +55,55 @@ func runTopology(cmd *cobra.Command, args []string) error { if err != nil { return err } - f, err := os.Create(topologyOutputFile) - logf.Log.V(1).Info("write topology topology to file", "file", topologyOutputFile, "error", 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 + } + + g, err := graphviz.New(ctx) + if err != nil { + return err + } + + graph, err := graphviz.ParseBytes([]byte(topologyConfigMap.Data["topology"])) + logf.Log.V(1).Info("parse DOT graph", "graph empty", graph == nil, "error", err) + if err != nil { + return err + } + + nodeNum, err := graph.NodeNum() + logf.Log.V(1).Info("info graph", "graph nodenum", nodeNum, "error", err) + if err != nil { + return err + } + + // 1. write encoded PNG data to buffer + var buf bytes.Buffer + err = g.Render(ctx, graph, graphviz.SVG, &buf) + logf.Log.V(1).Info("render graph to SVG", "buf len", buf.Len(), "error", err) + if err != nil { + return err + } + + // write to file + fSvg, err := os.Create(topologyOutputFile) if err != nil { return err } - defer f.Close() + defer fSvg.Close() - _, err = f.WriteString(topologyConfigMap.Data["topology"]) + _, err = fSvg.Write(buf.Bytes()) + logf.Log.V(1).Info("write topology in SVG format to file", "file", topologyOutputFile, "error", err) if err != nil { return err } diff --git a/go.mod b/go.mod index 2b4b3ad..86399dd 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,37 @@ module github.com/kuadrant/kuadrantctl -go 1.21 +go 1.22.0 + +toolchain go1.22.5 require ( github.com/getkin/kin-openapi v0.120.0 github.com/ghodss/yaml v1.0.0 + github.com/goccy/go-graphviz v0.2.9 github.com/kuadrant/authorino v0.15.0 github.com/kuadrant/kuadrant-operator v0.7.1 github.com/onsi/ginkgo/v2 v2.13.2 github.com/onsi/gomega v1.30.0 - github.com/operator-framework/api v0.19.0 github.com/spf13/cobra v1.8.0 - k8s.io/apiextensions-apiserver v0.28.4 + k8s.io/api v0.28.4 k8s.io/apimachinery v0.28.4 k8s.io/client-go v0.28.4 k8s.io/utils v0.0.0-20231127182322-b307cd553661 sigs.k8s.io/controller-runtime v0.16.3 sigs.k8s.io/gateway-api v1.0.1-0.20231204134048-c7da42e6eafc + sigs.k8s.io/yaml v1.4.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/disintegration/imaging v1.6.2 // indirect github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect + github.com/flopp/go-findfont v0.1.0 // indirect + github.com/fogleman/gg v1.3.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/zapr v1.2.4 // indirect @@ -35,6 +40,7 @@ require ( github.com/go-openapi/swag v0.22.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect @@ -47,7 +53,6 @@ require ( github.com/invopop/yaml v0.2.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kuadrant/limitador-operator v0.7.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -62,34 +67,34 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/tetratelabs/wazero v1.8.1 // indirect github.com/tidwall/gjson v1.14.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/image v0.21.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect + golang.org/x/text v0.19.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.28.4 // indirect + k8s.io/apiextensions-apiserver v0.28.4 // indirect k8s.io/component-base v0.28.4 // indirect k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20231129212854-f0671cc7e66a // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) replace github.com/imdario/mergo => dario.cat/mergo v0.3.5 diff --git a/go.sum b/go.sum index fca2753..d1530ee 100644 --- a/go.sum +++ b/go.sum @@ -3,16 +3,18 @@ dario.cat/mergo v0.3.5/go.mod h1:fvkCdyGtdx6UQvuEimZ9mB2dzc2AymrLoRgHC4lz6ec= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI= +github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk= github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= @@ -21,6 +23,10 @@ github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU= +github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw= +github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg= @@ -44,8 +50,12 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/goccy/go-graphviz v0.2.9 h1:4yD2MIMpxNt+sOEARDh5jTE2S/jeAKi92w72B83mWGg= +github.com/goccy/go-graphviz v0.2.9/go.mod h1:hssjl/qbvUXGmloY81BwXt2nqoApKo7DFgDj5dLJGb8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -102,12 +112,12 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/operator-framework/api v0.19.0 h1:QU1CTJU+CufoeneA5rsNlP/uP96s8vDHWUYDFZTauzA= -github.com/operator-framework/api v0.19.0/go.mod h1:SCCslqke6AVOJ5JM+NqNE1CHuAgJLScsL66pnPaSMXs= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -127,8 +137,6 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -144,6 +152,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= +github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -172,13 +182,14 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= +golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -187,8 +198,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -204,20 +215,19 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -227,8 +237,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 9eb4601363e4697f5097d983195feeb9e59e58ba Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 19 Dec 2024 13:58:58 +0100 Subject: [PATCH 3/7] =?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 4/7] 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 5/7] 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 6/7] 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 7/7] 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