From b5094bde55a7f670c9b1e729589594a198e84d58 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 20 May 2015 18:00:26 -0700 Subject: [PATCH] create Containers type Signed-off-by: Victor Vieux --- cluster/cluster.go | 4 ++- cluster/container.go | 69 ++++++++++++++++++++++++++++++++++++++- cluster/container_test.go | 58 ++++++++++++++++++++++++++++++++ cluster/engine.go | 4 +-- cluster/swarm/cluster.go | 56 ++----------------------------- 5 files changed, 134 insertions(+), 57 deletions(-) create mode 100644 cluster/container_test.go diff --git a/cluster/cluster.go b/cluster/cluster.go index d40729c3b8..b26b1d5dc7 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -24,9 +24,11 @@ type Cluster interface { RemoveImage(image *Image) ([]*dockerclient.ImageDelete, error) // Return all containers - Containers() []*Container + Containers() Containers // Return container the matching `IDOrName` + // TODO: remove this method from the interface as we can use + // cluster.Containers().Get(IDOrName) Container(IDOrName string) *Container // Pull images diff --git a/cluster/container.go b/cluster/container.go index 37407a96a0..3a90197040 100644 --- a/cluster/container.go +++ b/cluster/container.go @@ -1,6 +1,11 @@ package cluster -import "github.com/samalba/dockerclient" +import ( + "strings" + + "github.com/docker/docker/pkg/stringid" + "github.com/samalba/dockerclient" +) // Container is exported type Container struct { @@ -15,3 +20,65 @@ type Container struct { func (c *Container) Refresh() error { return c.Engine.refreshContainer(c.Id, true) } + +// Containers represents a list a containers +type Containers []*Container + +// Get returns a container using it's ID or Name +func (containers Containers) Get(IDOrName string) *Container { + // Abort immediately if the name is empty. + if len(IDOrName) == 0 { + return nil + } + + // Match exact or short Container ID. + for _, container := range containers { + if container.Id == IDOrName || stringid.TruncateID(container.Id) == IDOrName { + return container + } + } + + // Match exact Swarm ID. + for _, container := range containers { + if swarmID := container.Config.SwarmID(); swarmID == IDOrName || stringid.TruncateID(swarmID) == IDOrName { + return container + } + } + + candidates := []*Container{} + + // Match name, /name or engine/name. + for _, container := range containers { + for _, name := range container.Names { + if name == IDOrName || name == "/"+IDOrName || container.Engine.ID+name == IDOrName || container.Engine.Name+name == IDOrName { + return container + } + } + } + + if size := len(candidates); size == 1 { + return candidates[0] + } else if size > 1 { + return nil + } + + // Match Container ID prefix. + for _, container := range containers { + if strings.HasPrefix(container.Id, IDOrName) { + candidates = append(candidates, container) + } + } + + // Match Swarm ID prefix. + for _, container := range containers { + if strings.HasPrefix(container.Config.SwarmID(), IDOrName) { + candidates = append(candidates, container) + } + } + + if len(candidates) == 1 { + return candidates[0] + } + + return nil +} diff --git a/cluster/container_test.go b/cluster/container_test.go new file mode 100644 index 0000000000..1798dc496d --- /dev/null +++ b/cluster/container_test.go @@ -0,0 +1,58 @@ +package cluster + +import ( + "testing" + + "github.com/samalba/dockerclient" + "github.com/stretchr/testify/assert" +) + +func TestContainersGet(t *testing.T) { + containers := Containers([]*Container{{ + Container: dockerclient.Container{ + Id: "container1-id", + Names: []string{"/container1-name1", "/container1-name2"}, + }, + Engine: &Engine{ID: "test-engine"}, + Config: BuildContainerConfig(dockerclient.ContainerConfig{ + Labels: map[string]string{ + "com.docker.swarm.id": "swarm1-id", + }, + }), + }, { + Container: dockerclient.Container{ + Id: "container2-id", + Names: []string{"/con"}, + }, + Engine: &Engine{ID: "test-engine"}, + Config: BuildContainerConfig(dockerclient.ContainerConfig{ + Labels: map[string]string{ + "com.docker.swarm.id": "swarm2-id", + }, + }), + }}) + + // Invalid lookup + assert.Nil(t, containers.Get("invalid-id")) + assert.Nil(t, containers.Get("")) + // Container ID lookup. + assert.NotNil(t, containers.Get("container1-id")) + // Container ID prefix lookup. + assert.NotNil(t, containers.Get("container1-")) + assert.Nil(t, containers.Get("container")) + // Container name lookup. + assert.NotNil(t, containers.Get("container1-name1")) + assert.NotNil(t, containers.Get("container1-name2")) + // Container engine/name matching. + assert.NotNil(t, containers.Get("test-engine/container1-name1")) + assert.NotNil(t, containers.Get("test-engine/container1-name2")) + // Swarm ID lookup. + assert.NotNil(t, containers.Get("swarm1-id")) + // Swarm ID prefix lookup. + assert.NotNil(t, containers.Get("swarm1-")) + assert.Nil(t, containers.Get("swarm")) + // Get name before ID prefix + cc := containers.Get("con") + assert.NotNil(t, cc) + assert.Equal(t, cc.Id, "container2-id") +} diff --git a/cluster/engine.go b/cluster/engine.go index 419c75c0c2..2af25e2f22 100644 --- a/cluster/engine.go +++ b/cluster/engine.go @@ -452,9 +452,9 @@ func (e *Engine) RegisterEventHandler(h EventHandler) error { } // Containers returns all the containers in the engine. -func (e *Engine) Containers() []*Container { +func (e *Engine) Containers() Containers { e.RLock() - containers := make([]*Container, 0, len(e.containers)) + containers := Containers{} for _, container := range e.containers { containers = append(containers, container) } diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index 2ed1d7a9f6..32f01743ea 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -357,11 +357,11 @@ func (c *Cluster) Load(imageReader io.Reader, callback func(what, status string) } // Containers returns all the containers in the cluster. -func (c *Cluster) Containers() []*cluster.Container { +func (c *Cluster) Containers() cluster.Containers { c.RLock() defer c.RUnlock() - out := []*cluster.Container{} + out := cluster.Containers{} for _, n := range c.engines { out = append(out, n.Containers()...) } @@ -399,58 +399,8 @@ func (c *Cluster) Container(IDOrName string) *cluster.Container { c.RLock() defer c.RUnlock() - containers := c.Containers() + return cluster.Containers(c.Containers()).Get(IDOrName) - // Match exact or short Container ID. - for _, container := range containers { - if container.Id == IDOrName || stringid.TruncateID(container.Id) == IDOrName { - return container - } - } - - // Match exact Swarm ID. - for _, container := range containers { - if swarmID := container.Config.SwarmID(); swarmID == IDOrName || stringid.TruncateID(swarmID) == IDOrName { - return container - } - } - - candidates := []*cluster.Container{} - - // Match name, /name or engine/name. - for _, container := range containers { - for _, name := range container.Names { - if name == IDOrName || name == "/"+IDOrName || container.Engine.ID+name == IDOrName || container.Engine.Name+name == IDOrName { - return container - } - } - } - - if size := len(candidates); size == 1 { - return candidates[0] - } else if size > 1 { - return nil - } - - // Match Container ID prefix. - for _, container := range containers { - if strings.HasPrefix(container.Id, IDOrName) { - candidates = append(candidates, container) - } - } - - // Match Swarm ID prefix. - for _, container := range containers { - if strings.HasPrefix(container.Config.SwarmID(), IDOrName) { - candidates = append(candidates, container) - } - } - - if len(candidates) == 1 { - return candidates[0] - } - - return nil } // listNodes returns all the engines in the cluster.