Expose docker image id and name

This commit is contained in:
Tom Wilkie
2015-05-22 14:06:38 +00:00
parent f11168c051
commit 18c38a6bf4
4 changed files with 91 additions and 35 deletions

View File

@@ -36,6 +36,8 @@ func originNodeForProcess(node report.NodeMetadata) OriginNode {
for _, tuple := range []struct{ key, human string }{
{"docker_id", "Container ID"},
{"docker_name", "Container name"},
{"docker_image_id", "Container image ID"},
{"docker_image_name", "Container image name"},
{"cgroup", "cgroup"},
} {
if val, ok := node[tuple.key]; ok {

View File

@@ -11,14 +11,15 @@ import (
type dockerMapper struct {
sync.RWMutex
d map[int]*docker.Container
procRoot string
containers map[int]*docker.Container
images map[string]*docker.APIImages
procRoot string
}
func newDockerMapper(procRoot string, interval time.Duration) *dockerMapper {
m := dockerMapper{
procRoot: procRoot,
d: map[int]*docker.Container{},
procRoot: procRoot,
containers: map[int]*docker.Container{},
}
m.update()
go m.loop(interval)
@@ -35,6 +36,7 @@ func (m *dockerMapper) loop(d time.Duration) {
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) {
@@ -88,41 +90,71 @@ func (m *dockerMapper) update() {
}
}
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.d = pmap
m.containers = pmap
m.images = imageMap
m.Unlock()
}
type dockerIDMapper struct {
type dockerProcessMapper struct {
*dockerMapper
key string
f func(*docker.Container) string
}
func (m dockerIDMapper) Key() string { return "docker_id" }
func (m dockerIDMapper) Map(pid uint) (string, error) {
func (m *dockerProcessMapper) Key() string { return m.key }
func (m *dockerProcessMapper) Map(pid uint) (string, error) {
m.RLock()
container, ok := m.d[int(pid)]
container, ok := m.containers[int(pid)]
m.RUnlock()
if !ok {
return "", fmt.Errorf("no container found for PID %d", pid)
}
return container.ID, nil
return m.f(container), nil
}
type dockerNameMapper struct {
*dockerMapper
func (m *dockerMapper) idMapper() processMapper {
return &dockerProcessMapper{m, "docker_id", func(c *docker.Container) string {
return c.ID
}}
}
func (m dockerNameMapper) Key() string { return "docker_name" }
func (m dockerNameMapper) Map(pid uint) (string, error) {
m.RLock()
container, ok := m.d[int(pid)]
m.RUnlock()
if !ok {
return "", fmt.Errorf("no container found for PID %d", pid)
}
return container.Name, nil
func (m *dockerMapper) nameMapper() processMapper {
return &dockerProcessMapper{m, "docker_name", func(c *docker.Container) string {
return 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]
}}
}

View File

@@ -8,16 +8,21 @@ import (
)
type mockDockerClient struct {
containers []docker.APIContainers
containerInfo map[string]*docker.Container
apiContainers []docker.APIContainers
containers map[string]*docker.Container
apiImages []docker.APIImages
}
func (m mockDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
return m.containers, nil
return m.apiContainers, nil
}
func (m mockDockerClient) InspectContainer(id string) (*docker.Container, error) {
return m.containerInfo[id], nil
return m.containers[id], nil
}
func (m mockDockerClient) ListImages(options docker.ListImagesOptions) ([]docker.APIImages, error) {
return m.apiImages, nil
}
func TestDockerProcessMapper(t *testing.T) {
@@ -41,24 +46,28 @@ func TestDockerProcessMapper(t *testing.T) {
newDockerClient = func(endpoint string) (dockerClient, error) {
return mockDockerClient{
containers: []docker.APIContainers{{ID: "foo"}},
containerInfo: map[string]*docker.Container{
apiContainers: []docker.APIContainers{{ID: "foo"}},
containers: map[string]*docker.Container{
"foo": {
ID: "foo",
Name: "bar",
Image: "baz",
State: docker.State{Pid: 1, Running: true},
},
},
apiImages: []docker.APIImages{{ID: "baz", RepoTags: []string{"tag"}}},
}, nil
}
dockerMapper := newDockerMapper("/proc", 10*time.Second)
dockerIDMapper := dockerIDMapper{dockerMapper}
dockerNameMapper := dockerNameMapper{dockerMapper}
dockerIDMapper := dockerMapper.idMapper()
dockerNameMapper := dockerMapper.nameMapper()
dockerImageIDMapper := dockerMapper.imageIDMapper()
dockerImageNameMapper := dockerMapper.imageNameMapper()
for pid, want := range map[uint]struct{ id, name string }{
1: {"foo", "bar"},
2: {"foo", "bar"},
for pid, want := range map[uint]struct{ id, name, imageID, imageName string }{
1: {"foo", "bar", "baz", "tag"},
2: {"foo", "bar", "baz", "tag"},
} {
haveID, err := dockerIDMapper.Map(pid)
if err != nil || want.id != haveID {
@@ -68,5 +77,13 @@ func TestDockerProcessMapper(t *testing.T) {
if err != nil || want.name != haveName {
t.Errorf("%d: want %q, have %q (%v)", pid, want.name, haveName, err)
}
haveImageID, err := dockerImageIDMapper.Map(pid)
if err != nil || want.imageID != haveImageID {
t.Errorf("%d: want %q, have %q (%v)", pid, want.imageID, haveImageID, err)
}
haveImageName, err := dockerImageNameMapper.Map(pid)
if err != nil || want.imageName != haveImageName {
t.Errorf("%d: want %q, have %q (%v)", pid, want.imageName, haveImageName, err)
}
}
}

View File

@@ -79,7 +79,12 @@ func main() {
if *dockerMapper {
docker := newDockerMapper(*procRoot, *dockerInterval)
pms = append(pms, &dockerIDMapper{docker}, &dockerNameMapper{docker})
pms = append(pms,
docker.idMapper(),
docker.nameMapper(),
docker.imageIDMapper(),
docker.imageNameMapper(),
)
}
log.Printf("listening on %s", *listen)