Merge pull request #5 from justone/direct_client

Direct client access
This commit is contained in:
Nate Jones 2015-05-21 22:33:51 -07:00
commit 0940ffa495
5 changed files with 189 additions and 35 deletions

View file

@ -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
@ -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
@ -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
@ -101,4 +104,3 @@ See the [releases](https://github.com/justone/dockviz/releases) area for binarie
go get ./...
go build
```

14
cli.go
View file

@ -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)
}

View file

@ -1,6 +1,8 @@
package main
import (
"github.com/fsouza/go-dockerclient"
"bytes"
"encoding/json"
"fmt"
@ -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 {
@ -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

View file

@ -1,6 +1,8 @@
package main
import (
"github.com/fsouza/go-dockerclient"
"bytes"
"encoding/json"
"fmt"
@ -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 {

51
util.go Normal file
View file

@ -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
}