Skip to content

Commit

Permalink
Merge pull request #5 from justone/direct_client
Browse files Browse the repository at this point in the history
Direct client access
  • Loading branch information
justone committed May 22, 2015
2 parents ced348b + 961ed9e commit 0940ffa
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 35 deletions.
46 changes: 24 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
# dockviz
# dockviz: Visualizing Docker Data

Visualizing Docker Data
This command takes Docker image and container information and presents in
different ways, to help you understand what's going on inside the system.

This command takes the raw Docker JSON and visualizes it in various ways.
# Quick Start

For image information, output can be formatted as
[Graphviz](http://www.graphviz.org), as a tree in the terminal, or in a short summary.
1. Download the [latest release](https://github.com/justone/dockviz/releases).
2. Visualize images by running `dockviz images -t`, which has similar output to `docker images -t`.

For container information, only Graphviz output has been implemented.
Image can be visualized as [Graphviz](http://www.graphviz.org), or as a tree or short summary in the terminal. Only Graphviz output has been implemented for containers.

# Examples
# Output Examples

## Containers

Currently, containers are visualized with labeled lines for links. Containers that aren't running are greyed out.

```
$ dockviz containers -d | dot -Tpng -o containers.png
```

![](sample/containers.png "Container")

## Images

Image info is visualized with lines indicating parent images:

```
$ dockviz images -d | dot -Tpng -o images.png
```

![](sample/images.png "Image")

Or in short form:

```
$ dockviz images -s
nate/mongodb: latest
redis: latest
ubuntu: 12.04, precise, 12.10, quantal, 13.04, raring
Expand All @@ -34,6 +44,7 @@ ubuntu: 12.04, precise, 12.10, quantal, 13.04, raring
Or as a tree in the terminal:

```
$ dockviz images -t
└─511136ea3c5a Virtual Size: 0.0 B
|─f10ebce2c0e1 Virtual Size: 103.7 MB
| └─82cdea7ab5b5 Virtual Size: 103.9 MB
Expand Down Expand Up @@ -67,29 +78,21 @@ Or as a tree in the terminal:

# Running

## TCP
Dockviz supports connecting to the Docker daemon directly. It defaults to `unix:///var/run/docker.sock`, but respects the following as well:

When docker is listening on the TCP port:
* The `DOCKER_HOST`, `DOCKER_CERT_PATH`, and `DOCKER_TLS_VERIFY` environment variables, as set up by [boot2docker](http://boot2docker.io/) or [docker-machine](https://docs.docker.com/machine/).
* Command line arguments (e.g. `--tlscacert`), like those that Docker itself supports.

Dockviz also supports receiving Docker image or container json data on standard input.

```
$ curl -s http://localhost:4243/images/json?all=1 | dockviz images --tree
$ curl -s http://localhost:4243/containers/json?all=1 | dockviz containers --dot | dot -Tpng -o containers.png
```

## Socket

When docker is listening on the socket:

```
$ echo -e "GET /images/json?all=1 HTTP/1.0\r\n" | nc -U /var/run/docker.sock | tail -n +5 | dockviz images --tree
$ echo -e "GET /containers/json?all=1 HTTP/1.0\r\n" | nc -U /var/run/docker.sock | tail -n +5 | dockviz containers --dot | dot -Tpng -o containers.png
```

GNU netcat doesn't support `-U` (UNIX socket) flag, so OpenBSD variant can be used.

## Direct from Docker

Someday soon the Docker command line will allow dumping the image and container JSON directly.
Note: GNU netcat doesn't support `-U` (UNIX socket) flag, so OpenBSD variant can be used.

# Binaries

Expand All @@ -101,4 +104,3 @@ See the [releases](https://github.com/justone/dockviz/releases) area for binarie
go get ./...
go build
```

14 changes: 13 additions & 1 deletion cli.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
package main

import (
"fmt"
"os"

"github.com/jessevdk/go-flags"
)

type GlobalOptions struct {
// no options yet
TLSCaCert string `long:"tlscacert" value-name:"~/.docker/ca.pem" description:"Trust certs signed only by this CA"`
TLSCert string `long:"tlscert" value-name:"~/.docker/cert.pem" description:"Path to TLS certificate file"`
TLSKey string `long:"tlskey" value-name:"~/.docker/key.pem" description:"Path to TLS key file"`
TLSVerify bool `long:"tlsverify" description:"Use TLS and verify the remote"`
Host string `long:"host" short:"H" value-name:"unix:///var/run/docker.sock" description:"Docker host to connect to"`
Version func() `long:"version" short:"v" description:"Display version information."`
}

var globalOptions GlobalOptions
var parser = flags.NewParser(&globalOptions, flags.Default)

var version = "v0.2"

func main() {
globalOptions.Version = func() {
fmt.Println("dockviz", version)
os.Exit(0)
}
if _, err := parser.Parse(); err != nil {
os.Exit(1)
}
Expand Down
63 changes: 57 additions & 6 deletions containers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
"github.com/fsouza/go-dockerclient"

"bytes"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -28,15 +30,50 @@ var containersCommand ContainersCommand

func (x *ContainersCommand) Execute(args []string) error {

// read in stdin
stdin, err := ioutil.ReadAll(os.Stdin)
var containers *[]Container

stat, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("error reading all input", err)
return fmt.Errorf("error reading stdin stat", err)
}

containers, err := parseContainersJSON(stdin)
if err != nil {
return err
if (stat.Mode() & os.ModeCharDevice) == 0 {
// read in stdin
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("error reading all input", err)
}

containers, err = parseContainersJSON(stdin)
if err != nil {
return err
}
} else {

client, err := connect()
if err != nil {
return err
}

clientContainers, err := client.ListContainers(docker.ListContainersOptions{All: true})
if err != nil {
return err
}

var conts []Container
for _, container := range clientContainers {
conts = append(conts, Container{
container.ID,
container.Image,
container.Names,
apiPortToMap(container.Ports),
container.Created,
container.Status,
container.Command,
})
}

containers = &conts
}

if containersCommand.Dot {
Expand All @@ -48,6 +85,20 @@ func (x *ContainersCommand) Execute(args []string) error {
return nil
}

func apiPortToMap(ports []docker.APIPort) []map[string]interface{} {
result := make([]map[string]interface{}, 2)
for _, port := range ports {
intPort := map[string]interface{}{
"IP": port.IP,
"Type": port.Type,
"PrivatePort": port.PrivatePort,
"PublicPort": port.PublicPort,
}
result = append(result, intPort)
}
return result
}

func parseContainersJSON(rawJSON []byte) (*[]Container, error) {

var containers []Container
Expand Down
50 changes: 44 additions & 6 deletions images.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
"github.com/fsouza/go-dockerclient"

"bytes"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -29,15 +31,51 @@ var imagesCommand ImagesCommand

func (x *ImagesCommand) Execute(args []string) error {

// read in stdin
stdin, err := ioutil.ReadAll(os.Stdin)
var images *[]Image

stat, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("error reading all input", err)
return fmt.Errorf("error reading stdin stat", err)
}

images, err := parseImagesJSON(stdin)
if err != nil {
return err
if (stat.Mode() & os.ModeCharDevice) == 0 {
// read in stdin
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("error reading all input", err)
}

images, err = parseImagesJSON(stdin)
if err != nil {
return err
}

} else {

client, err := connect()
if err != nil {
return err
}

clientImages, err := client.ListImages(docker.ListImagesOptions{All: true})
if err != nil {
return err
}

var ims []Image
for _, image := range clientImages {
// fmt.Println(image)
ims = append(ims, Image{
image.ID,
image.ParentID,
image.RepoTags,
image.VirtualSize,
image.Size,
image.Created,
})
}

images = &ims
}

if imagesCommand.Dot {
Expand Down
51 changes: 51 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"errors"
"os"
"path"

"github.com/fsouza/go-dockerclient"
)

func connect() (*docker.Client, error) {

// grab directly from docker daemon
var endpoint string
if env_endpoint := os.Getenv("DOCKER_HOST"); len(env_endpoint) > 0 {
endpoint = env_endpoint
} else if len(globalOptions.Host) > 0 {
endpoint = globalOptions.Host
} else {
// assume local socket
endpoint = "unix:///var/run/docker.sock"
}

var client *docker.Client
var err error
dockerTlsVerifyEnv := os.Getenv("DOCKER_TLS_VERIFY")
if dockerTlsVerifyEnv == "1" || globalOptions.TLSVerify {
if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); len(dockerCertPath) > 0 {
cert := path.Join(dockerCertPath, "cert.pem")
key := path.Join(dockerCertPath, "key.pem")
ca := path.Join(dockerCertPath, "ca.pem")
client, err = docker.NewTLSClient(endpoint, cert, key, ca)
if err != nil {
return nil, err
}
} else if len(globalOptions.TLSCert) > 0 && len(globalOptions.TLSKey) > 0 && len(globalOptions.TLSCaCert) > 0 {
client, err = docker.NewTLSClient(endpoint, globalOptions.TLSCert, globalOptions.TLSKey, globalOptions.TLSCaCert)
if err != nil {
return nil, err
}
} else {
return nil, errors.New("TLS Verification requested but certs not specified")
}
} else {
client, err = docker.NewClient(endpoint)
if err != nil {
return nil, err
}
}
return client, nil
}

0 comments on commit 0940ffa

Please sign in to comment.