mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 18:51:17 +00:00
145 lines
3.1 KiB
Go
145 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
docker "github.com/fsouza/go-dockerclient"
|
|
)
|
|
|
|
// DockerClient internal data structure
|
|
type DockerClient struct {
|
|
store *Store
|
|
client *docker.Client
|
|
}
|
|
|
|
// NewDockerClient instantiates a new DockerClient
|
|
func NewDockerClient(store *Store) (*DockerClient, error) {
|
|
dc, err := docker.NewClient("unix:///var/run/docker.sock")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to connect to docker daemon: %v", err)
|
|
}
|
|
return &DockerClient{
|
|
store: store,
|
|
client: dc,
|
|
}, nil
|
|
}
|
|
|
|
// Start docker client
|
|
func (c *DockerClient) Start() {
|
|
for {
|
|
func() {
|
|
events := make(chan *docker.APIEvents)
|
|
if err := c.client.AddEventListener(events); err != nil {
|
|
log.Error(err)
|
|
return
|
|
}
|
|
defer func() {
|
|
if err := c.client.RemoveEventListener(events); err != nil {
|
|
log.Error(err)
|
|
}
|
|
}()
|
|
if err := c.getContainers(); err != nil {
|
|
log.Error(err)
|
|
return
|
|
}
|
|
for {
|
|
event, ok := <-events
|
|
if !ok {
|
|
log.Error("event listener unexpectedly disconnected")
|
|
return
|
|
}
|
|
c.handleEvent(event)
|
|
}
|
|
}()
|
|
time.Sleep(time.Second)
|
|
}
|
|
}
|
|
|
|
func (c *DockerClient) getContainers() error {
|
|
apiContainers, err := c.client.ListContainers(docker.ListContainersOptions{All: true})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, apiContainer := range apiContainers {
|
|
containerState, err := c.getContainerState(apiContainer.ID)
|
|
if err != nil {
|
|
log.Error(err)
|
|
continue
|
|
}
|
|
state := Destroyed
|
|
switch {
|
|
case containerState.Dead || containerState.Paused || containerState.Restarting || containerState.OOMKilled:
|
|
state = Stopped
|
|
case containerState.Running:
|
|
state = Running
|
|
}
|
|
c.updateContainer(apiContainer.ID, state, containerState.Pid)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *DockerClient) handleEvent(event *docker.APIEvents) {
|
|
var state State
|
|
switch event.Status {
|
|
case "create":
|
|
state = Created
|
|
case "destroy":
|
|
state = Destroyed
|
|
case "start", "unpause":
|
|
state = Running
|
|
case "die", "pause":
|
|
state = Stopped
|
|
default:
|
|
return
|
|
}
|
|
pid, err := c.getContainerPID(event.ID)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return
|
|
}
|
|
c.updateContainer(event.ID, state, pid)
|
|
}
|
|
|
|
func (c *DockerClient) getContainerPID(containerID string) (int, error) {
|
|
containerState, err := c.getContainerState(containerID)
|
|
if containerState == nil {
|
|
return 0, err
|
|
}
|
|
return containerState.Pid, nil
|
|
}
|
|
|
|
func (c *DockerClient) getContainerState(containerID string) (*docker.State, error) {
|
|
dockerContainer, err := c.getContainer(containerID)
|
|
if dockerContainer == nil {
|
|
return nil, err
|
|
}
|
|
return &dockerContainer.State, nil
|
|
}
|
|
|
|
func (c *DockerClient) getContainer(containerID string) (*docker.Container, error) {
|
|
dockerContainer, err := c.client.InspectContainer(containerID)
|
|
if err != nil {
|
|
if _, ok := err.(*docker.NoSuchContainer); !ok {
|
|
return nil, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
return dockerContainer, nil
|
|
}
|
|
|
|
func (c *DockerClient) updateContainer(containerID string, state State, pid int) {
|
|
if state == Destroyed {
|
|
c.store.DeleteContainer(containerID)
|
|
return
|
|
}
|
|
cont := Container{
|
|
State: state,
|
|
PID: pid,
|
|
}
|
|
c.store.SetContainer(containerID, cont)
|
|
}
|