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

topology command: persist in local disk #104

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
Expand All @@ -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
}
135 changes: 135 additions & 0 deletions cmd/topology.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package cmd

import (
"bytes"
"errors"
"os"
"os/exec"
"strings"

"github.com/goccy/go-graphviz"
"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
topologySVGOutputFile string
topologyDOTOutputFile string
)

func topologyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "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(&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)
}
return cmd
}

func runTopology(cmd *cobra.Command, args []string) error {
if !strings.HasSuffix(topologySVGOutputFile, ".svg") {
return errors.New("output file must have .svg extension")
}
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
}

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)
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(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", topologySVGOutputFile, "error", err)
if err != nil {
return err
}

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

// 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
}
6 changes: 0 additions & 6 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/spf13/cobra"

"github.com/kuadrant/kuadrantctl/pkg/utils"
"github.com/kuadrant/kuadrantctl/version"
)

Expand All @@ -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
},
Expand Down
31 changes: 18 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading
Loading