mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
162 lines
3.3 KiB
Go
162 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
docker "github.com/fsouza/go-dockerclient"
|
|
)
|
|
|
|
type dockerMapper struct {
|
|
sync.RWMutex
|
|
containers map[int]*docker.Container
|
|
images map[string]*docker.APIImages
|
|
procRoot string
|
|
}
|
|
|
|
func newDockerMapper(procRoot string, interval time.Duration) *dockerMapper {
|
|
m := dockerMapper{
|
|
procRoot: procRoot,
|
|
containers: map[int]*docker.Container{},
|
|
}
|
|
m.update()
|
|
go m.loop(interval)
|
|
return &m
|
|
}
|
|
|
|
func (m *dockerMapper) loop(d time.Duration) {
|
|
for range time.Tick(d) {
|
|
m.update()
|
|
}
|
|
}
|
|
|
|
// for mocking
|
|
type dockerClient interface {
|
|
ListContainers(docker.ListContainersOptions) ([]docker.APIContainers, error)
|
|
InspectContainer(string) (*docker.Container, error)
|
|
ListImages(docker.ListImagesOptions) ([]docker.APIImages, error)
|
|
}
|
|
|
|
func newRealDockerClient(endpoint string) (dockerClient, error) {
|
|
return docker.NewClient(endpoint)
|
|
}
|
|
|
|
var (
|
|
newDockerClient = newRealDockerClient
|
|
newPIDTreeStub = newPIDTree
|
|
)
|
|
|
|
func (m *dockerMapper) update() {
|
|
pidTree, err := newPIDTreeStub(m.procRoot)
|
|
if err != nil {
|
|
log.Printf("docker mapper: %s", err)
|
|
return
|
|
}
|
|
|
|
endpoint := "unix:///var/run/docker.sock"
|
|
client, err := newDockerClient(endpoint)
|
|
if err != nil {
|
|
log.Printf("docker mapper: %s", err)
|
|
return
|
|
}
|
|
|
|
containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
|
if err != nil {
|
|
log.Printf("docker mapper: %s", err)
|
|
return
|
|
}
|
|
|
|
pmap := map[int]*docker.Container{}
|
|
for _, container := range containers {
|
|
info, err := client.InspectContainer(container.ID)
|
|
if err != nil {
|
|
log.Printf("docker mapper: %s", err)
|
|
continue
|
|
}
|
|
|
|
if !info.State.Running {
|
|
continue
|
|
}
|
|
|
|
pids, err := pidTree.allChildren(info.State.Pid)
|
|
if err != nil {
|
|
log.Printf("docker mapper: %s", err)
|
|
continue
|
|
}
|
|
for _, pid := range pids {
|
|
pmap[pid] = info
|
|
}
|
|
}
|
|
|
|
imageList, err := client.ListImages(docker.ListImagesOptions{})
|
|
if err != nil {
|
|
log.Printf("docker mapper: %s", err)
|
|
return
|
|
}
|
|
|
|
imageMap := map[string]*docker.APIImages{}
|
|
for i := range imageList {
|
|
image := &imageList[i]
|
|
imageMap[image.ID] = image
|
|
}
|
|
|
|
m.Lock()
|
|
m.containers = pmap
|
|
m.images = imageMap
|
|
m.Unlock()
|
|
}
|
|
|
|
type dockerProcessMapper struct {
|
|
*dockerMapper
|
|
key string
|
|
f func(*docker.Container) string
|
|
}
|
|
|
|
func (m *dockerProcessMapper) Key() string { return m.key }
|
|
func (m *dockerProcessMapper) Map(pid uint) (string, error) {
|
|
m.RLock()
|
|
container, ok := m.containers[int(pid)]
|
|
m.RUnlock()
|
|
|
|
if !ok {
|
|
return "", fmt.Errorf("no container found for PID %d", pid)
|
|
}
|
|
|
|
return m.f(container), nil
|
|
}
|
|
|
|
func (m *dockerMapper) idMapper() processMapper {
|
|
return &dockerProcessMapper{m, "docker_id", func(c *docker.Container) string {
|
|
return c.ID
|
|
}}
|
|
}
|
|
|
|
func (m *dockerMapper) nameMapper() processMapper {
|
|
return &dockerProcessMapper{m, "docker_name", func(c *docker.Container) string {
|
|
return strings.TrimPrefix(c.Name, "/")
|
|
}}
|
|
}
|
|
|
|
func (m *dockerMapper) imageIDMapper() processMapper {
|
|
return &dockerProcessMapper{m, "docker_image_id", func(c *docker.Container) string {
|
|
return c.Image
|
|
}}
|
|
}
|
|
|
|
func (m *dockerMapper) imageNameMapper() processMapper {
|
|
return &dockerProcessMapper{m, "docker_image_name", func(c *docker.Container) string {
|
|
m.RLock()
|
|
image, ok := m.images[c.Image]
|
|
m.RUnlock()
|
|
|
|
if !ok || len(image.RepoTags) == 0 {
|
|
return ""
|
|
}
|
|
|
|
return image.RepoTags[0]
|
|
}}
|
|
}
|