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 1. Download the [latest release](https://github.com/justone/dockviz/releases).
[Graphviz](http://www.graphviz.org), as a tree in the terminal, or in a short summary. 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 ## Containers
Currently, containers are visualized with labeled lines for links. Containers that aren't running are greyed out. 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") ![](sample/containers.png "Container")
## Images ## Images
Image info is visualized with lines indicating parent images: Image info is visualized with lines indicating parent images:
```
$ dockviz images -d | dot -Tpng -o images.png
```
![](sample/images.png "Image") ![](sample/images.png "Image")
Or in short form: Or in short form:
``` ```
$ dockviz images -s
nate/mongodb: latest nate/mongodb: latest
redis: latest redis: latest
ubuntu: 12.04, precise, 12.10, quantal, 13.04, raring 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: Or as a tree in the terminal:
``` ```
$ dockviz images -t
└─511136ea3c5a Virtual Size: 0.0 B └─511136ea3c5a Virtual Size: 0.0 B
|─f10ebce2c0e1 Virtual Size: 103.7 MB |─f10ebce2c0e1 Virtual Size: 103.7 MB
| └─82cdea7ab5b5 Virtual Size: 103.9 MB | └─82cdea7ab5b5 Virtual Size: 103.9 MB
@ -67,29 +78,21 @@ Or as a tree in the terminal:
# Running # 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/images/json?all=1 | dockviz images --tree
$ curl -s http://localhost:4243/containers/json?all=1 | dockviz containers --dot | dot -Tpng -o containers.png $ 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 /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 $ 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. Note: 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.
# Binaries # Binaries
@ -101,4 +104,3 @@ See the [releases](https://github.com/justone/dockviz/releases) area for binarie
go get ./... go get ./...
go build go build
``` ```

14
cli.go
View file

@ -1,19 +1,31 @@
package main package main
import ( import (
"fmt"
"os" "os"
"github.com/jessevdk/go-flags" "github.com/jessevdk/go-flags"
) )
type GlobalOptions struct { 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 globalOptions GlobalOptions
var parser = flags.NewParser(&globalOptions, flags.Default) var parser = flags.NewParser(&globalOptions, flags.Default)
var version = "v0.2"
func main() { func main() {
globalOptions.Version = func() {
fmt.Println("dockviz", version)
os.Exit(0)
}
if _, err := parser.Parse(); err != nil { if _, err := parser.Parse(); err != nil {
os.Exit(1) os.Exit(1)
} }

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"github.com/fsouza/go-dockerclient"
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -28,16 +30,51 @@ var containersCommand ContainersCommand
func (x *ContainersCommand) Execute(args []string) error { func (x *ContainersCommand) Execute(args []string) error {
var containers *[]Container
stat, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("error reading stdin stat", err)
}
if (stat.Mode() & os.ModeCharDevice) == 0 {
// read in stdin // read in stdin
stdin, err := ioutil.ReadAll(os.Stdin) stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return fmt.Errorf("error reading all input", err) return fmt.Errorf("error reading all input", err)
} }
containers, err := parseContainersJSON(stdin) containers, err = parseContainersJSON(stdin)
if err != nil { if err != nil {
return err 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 { if containersCommand.Dot {
fmt.Printf(jsonContainersToDot(containers)) fmt.Printf(jsonContainersToDot(containers))
@ -48,6 +85,20 @@ func (x *ContainersCommand) Execute(args []string) error {
return nil 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) { func parseContainersJSON(rawJSON []byte) (*[]Container, error) {
var containers []Container var containers []Container

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"github.com/fsouza/go-dockerclient"
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -29,17 +31,53 @@ var imagesCommand ImagesCommand
func (x *ImagesCommand) Execute(args []string) error { func (x *ImagesCommand) Execute(args []string) error {
var images *[]Image
stat, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("error reading stdin stat", err)
}
if (stat.Mode() & os.ModeCharDevice) == 0 {
// read in stdin // read in stdin
stdin, err := ioutil.ReadAll(os.Stdin) stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return fmt.Errorf("error reading all input", err) return fmt.Errorf("error reading all input", err)
} }
images, err := parseImagesJSON(stdin) images, err = parseImagesJSON(stdin)
if err != nil { if err != nil {
return err 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 { if imagesCommand.Dot {
fmt.Printf(jsonToDot(images)) fmt.Printf(jsonToDot(images))
} else if imagesCommand.Tree { } else if imagesCommand.Tree {

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
}