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

Add flag for supplying path to directory containing icons #55

Open
wants to merge 3 commits into
base: master
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
160 changes: 102 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,31 @@ Currently, this only generates a diagram similar to https://github.com/kubernete
For examples of the generated diagrams, see [Examples](#examples) below.

## Implementations
There are two implementations, bash script version and go version. Bash script version is just a wrapper to run go version inside container.

There are two implementations, bash script version and go version. Bash script version is just a wrapper to run go version inside a Docker container.

## Prerequisites

### Bash script version

`k8sviz.sh` requires:

- bash
- getopt
- docker

To build a container image (optional), it requires:

- make

### Go version

`k8sviz` requires:

- dot (graphviz) command

To build binary, it requires:

- make
- go

Expand All @@ -33,33 +41,45 @@ To build binary, it requires:
| k8sviz 0.3.3 or later | No | Yes |

## Installation

### Bash script version

Just download `k8sviz.sh` file and add execute permission.

```shell
$ curl -LO https://raw.githubusercontent.com/mkimuram/k8sviz/master/k8sviz.sh
$ chmod u+x k8sviz.sh
curl -LO https://raw.githubusercontent.com/mkimuram/k8sviz/master/k8sviz.sh
chmod u+x k8sviz.sh
```

### Go version

Build the binary with below commands:

```shell
$ git clone https://github.com/mkimuram/k8sviz.git
$ cd k8sviz
$ make build
git clone https://github.com/mkimuram/k8sviz.git
cd k8sviz
make build
```

`icons` directory needs to be in the same directory to the k8sviz binary.
By default, the `icons` directory is expected to be in the same directory as the `k8sviz` binary.
So, move them to the proper directory (Replace `PATH_TO_INSTALL` as you like).

```shell
$ PATH_TO_INSTALL=$HOME/bin
$ cp bin/k8sviz ${PATH_TO_INSTALL}
$ cp -r icons ${PATH_TO_INSTALL}
PATH_TO_INSTALL=$HOME/bin
cp bin/k8sviz ${PATH_TO_INSTALL}
cp -r icons ${PATH_TO_INSTALL}
```

In case you wish to not put them in the same directory, you can run `k8sviz` with the command line flag `--icons` to pass the path to the directory containing the required icons.
The path can either be relative to the binary (e.g. `../share/icons`) or absolute (e.g. `/usr/share/k8sviz/icons`).

## Usage

### Bash script version

```shell
$ ./k8sviz.sh --help
> ./k8sviz.sh --help

USAGE: ./k8sviz.sh [flags] args
flags:
-n,--namespace: The namespace to visualize. (default: 'default')
Expand All @@ -72,89 +92,112 @@ flags:

- ⚠️ WARNING

If you are using Mac, only short options can be used.
If you would like to use long options, you can install gnu-getopt and enable it by defining
`FLAGS_GETOPT_CMD` environment variable.
```shell
$ brew install gnu-getopt
$ export FLAGS_GETOPT_CMD=/usr/local/opt/gnu-getopt/bin/getopt
$ ./k8sviz.sh -h
```
If you are using Mac, only short options can be used.
If you would like to use long options, you can install gnu-getopt and enable it by defining
`FLAGS_GETOPT_CMD` environment variable.

```shell
brew install gnu-getopt
export FLAGS_GETOPT_CMD=/usr/local/opt/gnu-getopt/bin/getopt
./k8sviz.sh -h
```

- 📝NOTE

If you can't pull the container image or need to build it by yourself,
you can do it by `make image-build`. It would be helpful if you specify
`DEVEL_IMAGE` and `DEVEL_TAG` to make the image name the same to the
default one (Below example will set image name like `mkimuram/k8sviz:0.3.4`).
```shell
$ DEVEL_IMAGE=mkimuram/k8sviz DEVEL_TAG=$(cat version.txt) make image-build
```

An example use case of creating custom image is to include AWS SDK or Google Cloud SDK.
To create a custom image that include AWS SDK, run below command:
```shell
$ DEVEL_IMAGE=mkimuram/k8sviz DEVEL_TAG=$(cat version.txt) TARGET=aws make image-build
```
To create a custom image that include Google Cloud SDK, run below command:
```shell
$ DEVEL_IMAGE=mkimuram/k8sviz DEVEL_TAG=$(cat version.txt) TARGET=gcloud make image-build
```
If you can't pull the container image or need to build it by yourself,
you can do it by `make image-build`. It would be helpful if you specify
`DEVEL_IMAGE` and `DEVEL_TAG` to make the image name the same to the
default one (Below example will set image name like `mkimuram/k8sviz:0.3.4`).

```shell
DEVEL_IMAGE=mkimuram/k8sviz DEVEL_TAG=$(cat version.txt) make image-build
```

An example use case of creating custom image is to include AWS SDK or Google Cloud SDK.
To create a custom image that include AWS SDK, run below command:

```shell
DEVEL_IMAGE=mkimuram/k8sviz DEVEL_TAG=$(cat version.txt) TARGET=aws make image-build
```

To create a custom image that include Google Cloud SDK, run below command:

```shell
DEVEL_IMAGE=mkimuram/k8sviz DEVEL_TAG=$(cat version.txt) TARGET=gcloud make image-build
```

### Go version

```shell
$ ./k8sviz -h
> ./k8sviz -h

Usage of ./k8sviz:
-i string
path of directory containing icons (shorthand) (default "icons")
-icons string
path of directory containing icons (default "icons")
-kubeconfig string
absolute path to the kubeconfig file (default "/home/user1/.kube/config")
absolute path to the kubeconfig file (default "/home/mathym/.kube/config")
-n string
namespace to visualize (shorthand) (default "default")
namespace to visualize (shorthand) (default "default")
-namespace string
namespace to visualize (default "default")
namespace to visualize (default "default")
-o string
output filename (shorthand) (default "k8sviz.out")
output filename (shorthand) (default "k8sviz.out")
-outfile string
output filename (default "k8sviz.out")
output filename (default "k8sviz.out")
-t string
type of output (shorthand) (default "dot")
type of output (shorthand) (default "dot")
-type string
type of output (default "dot")
type of output (default "dot")
```

## Examples

Examples are only shown for old bash script version, but current go version should work in the same way.

### Examples for tutorial deployments in default namespace

- Generate dot file for namespace `default`
```shell
./k8sviz.sh -n default -o default.dot
```

```shell
./k8sviz.sh -n default -o default.dot
```

- Generate png file for namespace `default`
```shell
$ ./k8sviz.sh -n default -t png -o default.png
```

```shell
./k8sviz.sh -n default -t png -o default.png
```

- Output for [an example wordpress deployment](https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/) will be like below:
- [default.dot](./examples/wordpress/default.dot)
- [default.png](./examples/wordpress/default.png):

<a href="https://raw.githubusercontent.com/mkimuram/k8sviz/master/examples/wordpress/default.png"><img src="https://raw.githubusercontent.com/mkimuram/k8sviz/master/examples/wordpress/default.png" width="40%" height="40%"/></a>

- Output for [an example cassandra deployment with statefulset](https://kubernetes.io/docs/tutorials/stateful-application/cassandra/) will be like below:
- [default.dot](./examples/cassandra/default.dot)
- [default.png](./examples/cassandra/default.png):

<a href="https://raw.githubusercontent.com/mkimuram/k8sviz/master/examples/cassandra/default.png"><img src="https://raw.githubusercontent.com/mkimuram/k8sviz/master/examples/cassandra/default.png" width="50%" height="50%"/></a>

### Examples for more complex deployment ([kubeflow](https://www.kubeflow.org/docs/started/k8s/kfctl-k8s-istio/) case)

- Generate dot file for namespace `kubeflow` and `istio-system`
```shell
$ ./k8sviz.sh -n kubeflow -o examples/kubeflow/kubeflow.dot
$ ./k8sviz.sh -n istio-system -o examples/kubeflow/istio-system.dot
```

```shell
./k8sviz.sh -n kubeflow -o examples/kubeflow/kubeflow.dot
./k8sviz.sh -n istio-system -o examples/kubeflow/istio-system.dot
```

- Generate png file for namespace `kubeflow` and `istio-system`
```shell
$ ./k8sviz.sh -n kubeflow -t png -o examples/kubeflow/kubeflow.png
$ ./k8sviz.sh -n istio-system -t png -o examples/kubeflow/istio-system.png
```

```shell
./k8sviz.sh -n kubeflow -t png -o examples/kubeflow/kubeflow.png
./k8sviz.sh -n istio-system -t png -o examples/kubeflow/istio-system.png
```

- Output:
- [kubeflow.dot](./examples/kubeflow/kubeflow.dot)
- [istio-system.dot](./examples/kubeflow/istio-system.dot)
Expand All @@ -167,4 +210,5 @@ Examples are only shown for old bash script version, but current go version shou
<a href="https://raw.githubusercontent.com/mkimuram/k8sviz/master/examples/kubeflow/istio-system.png"><img src="https://raw.githubusercontent.com/mkimuram/k8sviz/master/examples/kubeflow/istio-system.png" width="90%" height="90%"/></a>

## License

This project is licensed under the Apache License - see the [LICENSE file](./LICENSE) for details
21 changes: 20 additions & 1 deletion cmd/k8sviz/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ const (
defaultNamespace = "default"
defaultOutFile = "k8sviz.out"
defaultOutType = "dot"
defaultIconsDir = "icons"
descNamespaceOpt = "namespace to visualize"
descOutFileOpt = "output filename"
descOutTypeOpt = "type of output"
descIconsDirOpt = "path of directory containing icons"
descShortOptSuffix = " (shorthand)"
)

var (
clientset *kubernetes.Clientset
dir string
iconsPath string
// Flags
namespace string
outFile string
outType string
iconsDir string
)

func init() {
Expand All @@ -55,6 +59,8 @@ func init() {
flag.StringVar(&outFile, "o", defaultOutFile, descOutFileOpt+descShortOptSuffix)
flag.StringVar(&outType, "type", defaultOutType, descOutTypeOpt)
flag.StringVar(&outType, "t", defaultOutType, descOutTypeOpt+descShortOptSuffix)
flag.StringVar(&iconsDir, "icons", defaultIconsDir, descIconsDirOpt)
flag.StringVar(&iconsDir, "i", defaultIconsDir, descIconsDirOpt+descShortOptSuffix)
flag.Parse()

// use the current context in kubeconfig
Expand Down Expand Up @@ -83,6 +89,12 @@ func init() {
fmt.Fprintf(os.Stderr, "Failed to find the directory of this command: %v\n", err)
os.Exit(1)
}

if filepath.IsAbs(iconsDir) {
iconsPath = iconsDir
} else {
iconsPath = filepath.Join(dir, iconsDir)
}
}

func main() {
Expand All @@ -97,7 +109,14 @@ func main() {
os.Exit(1)
}

g := graph.NewGraph(res, dir)
if _, err := os.Stat(iconsPath); err != nil {
if os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "Icons cannot be found at path: %v\n", err)
os.Exit(1)
}
}

g := graph.NewGraph(res, dir, iconsPath)

if outType == "dot" {
if err := g.WriteDotFile(outFile); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion k8sviz.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#! /bin/bash
#!/usr/bin/env bash

#### Variables ####
NAMESPACE="default"
Expand Down
11 changes: 6 additions & 5 deletions pkg/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ import (

// Graph represents a graph of k8s resources
type Graph struct {
dir string
res *resources.Resources
gviz *gographviz.Graph
dir string
iconsPath string
res *resources.Resources
gviz *gographviz.Graph
}

// NewGraph returns a Graph of k8s resources
func NewGraph(res *resources.Resources, dir string) *Graph {
g := &Graph{res: res, dir: dir, gviz: gographviz.NewGraph()}
func NewGraph(res *resources.Resources, dir, iconsPath string) *Graph {
g := &Graph{res: res, dir: dir, iconsPath: iconsPath, gviz: gographviz.NewGraph()}
g.generate()

return g
Expand Down
6 changes: 3 additions & 3 deletions pkg/graph/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
var (
testns = "testns"
dir = "/testdir"
iconsPath = "/testdir/icons"
goldenDir = "testdata"
goldenSuffix = ".golden"
// if -update flag is specified on test run, golden file for the test will be updated
Expand Down Expand Up @@ -121,7 +122,7 @@ var (
OwnerReferences: []metav1.OwnerReference{{APIVersion: "batch/v1", Kind: "Job", Name: "job1"}}}},
&appsv1.DaemonSet{ObjectMeta: metav1.ObjectMeta{Namespace: testns, Name: "ds1"}},
&batchv1.Job{ObjectMeta: metav1.ObjectMeta{Namespace: testns, Name: "job1",
OwnerReferences: []metav1.OwnerReference{{APIVersion: "batch/v1beta1", Kind: "cronJob", Name: "cronjob1"}}}},
OwnerReferences: []metav1.OwnerReference{{APIVersion: "batch/v1beta1", Kind: "CronJob", Name: "cronjob1"}}}},
&batchv1.CronJob{ObjectMeta: metav1.ObjectMeta{Namespace: testns, Name: "cronjob1"}},
}
)
Expand All @@ -132,8 +133,7 @@ func prepTestGraph(t *testing.T, objs ...runtime.Object) *Graph {
if err != nil {
t.Fatalf("NewResources failed: %v", err)
}

return NewGraph(res, dir)
return NewGraph(res, dir, iconsPath)
}

func getGoldenFilePath(name string) string {
Expand Down
10 changes: 6 additions & 4 deletions pkg/graph/graph_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,24 @@ import (
)

// imagePath returns the path to the image file
// path is {dir}/icons/{resource}-128.png
// path is {dir}/{iconsDir}/{resource}-128.png
// ex) /icons/pod-128.png
func (g *Graph) imagePath(kind string) string {
return filepath.Join(g.dir, "icons", kind+imageSuffix)
return filepath.Join(g.iconsPath, kind+imageSuffix)
}

// clusterLabel returns the resource label for namespace
// ex)
// <<TABLE BORDER="0"><TR><TD><IMG SRC="/icons/ns-128.png" /></TD></TR><TR><TD>my-namespace</TD></TR></TABLE>>
//
// <<TABLE BORDER="0"><TR><TD><IMG SRC="/icons/ns-128.png" /></TD></TR><TR><TD>my-namespace</TD></TR></TABLE>>
func (g *Graph) clusterLabel() string {
return g.resourceLabel("ns", g.res.Namespace)
}

// resourceLabel returns the resource label for a resource
// ex)
// <<TABLE BORDER="0"><TR><TD><IMG SRC="/icons/pod-128.png" /></TD></TR><TR><TD>my-pod</TD></TR></TABLE>>
//
// <<TABLE BORDER="0"><TR><TD><IMG SRC="/icons/pod-128.png" /></TD></TR><TR><TD>my-pod</TD></TR></TABLE>>
func (g *Graph) resourceLabel(kind, name string) string {
return fmt.Sprintf("<<TABLE BORDER=\"0\"><TR><TD><IMG SRC=\"%s\" /></TD></TR><TR><TD>%s</TD></TR></TABLE>>", g.imagePath(kind), name)
}
Expand Down
Loading