Move container name matching logic into Node.

- Add `Node.Container()`
- Make `Cluster.Container()` use `Node.Container()`
- Added missing locks and converted existing ones to RLock.

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2015-02-10 10:36:31 -08:00
parent 7b009d6d43
commit 67e347fa1a
3 changed files with 71 additions and 13 deletions

View File

@ -3,7 +3,6 @@ package cluster
import (
"crypto/tls"
"errors"
"strings"
"sync"
log "github.com/Sirupsen/logrus"
@ -119,8 +118,8 @@ func (c *Cluster) UpdateNodes(entries []*discovery.Entry) {
// Containers returns all the containers in the cluster.
func (c *Cluster) Containers() []*Container {
c.Lock()
defer c.Unlock()
c.RLock()
defer c.RUnlock()
out := []*Container{}
for _, n := range c.nodes {
@ -139,19 +138,15 @@ func (c *Cluster) Container(IdOrName string) *Container {
if len(IdOrName) == 0 {
return nil
}
for _, container := range c.Containers() {
// Match ID prefix.
if strings.HasPrefix(container.Id, IdOrName) {
return container
}
// Match name, /name or engine/name.
for _, name := range container.Names {
if name == IdOrName || name == "/"+IdOrName || container.Node.ID+name == IdOrName || container.Node.Name+name == IdOrName {
c.RLock()
defer c.RUnlock()
for _, n := range c.nodes {
if container := n.Container(IdOrName); container != nil {
return container
}
}
}
return nil
}

View File

@ -394,6 +394,7 @@ func (n *Node) Events(h EventHandler) error {
return nil
}
// Containers returns all the containers in the node.
func (n *Node) Containers() []*Container {
containers := []*Container{}
n.RLock()
@ -404,6 +405,33 @@ func (n *Node) Containers() []*Container {
return containers
}
// Container returns the container with IdOrName in the node.
func (n *Node) Container(IdOrName string) *Container {
// Abort immediately if the name is empty.
if len(IdOrName) == 0 {
return nil
}
n.RLock()
defer n.RUnlock()
for _, container := range n.Containers() {
// Match ID prefix.
if strings.HasPrefix(container.Id, IdOrName) {
return container
}
// Match name, /name or engine/name.
for _, name := range container.Names {
if name == IdOrName || name == "/"+IdOrName || container.Node.ID+name == IdOrName || container.Node.Name+name == IdOrName {
return container
}
}
}
return nil
}
func (n *Node) Images() []*dockerclient.Image {
images := []*dockerclient.Image{}
n.RLock()
@ -416,6 +444,9 @@ func (n *Node) Images() []*dockerclient.Image {
// Image returns the image with IdOrName in the node
func (n *Node) Image(IdOrName string) *dockerclient.Image {
n.RLock()
defer n.RUnlock()
size := len(IdOrName)
for _, image := range n.Images() {
if image.Id == IdOrName || (size > 2 && strings.HasPrefix(image.Id, IdOrName)) {

View File

@ -135,6 +135,38 @@ func TestNodeState(t *testing.T) {
client.Mock.AssertExpectations(t)
}
func TestNodeContainerLookup(t *testing.T) {
node := NewNode("test-node", 0)
assert.False(t, node.IsConnected())
client := mockclient.NewMockClient()
client.On("Info").Return(mockInfo, nil)
client.On("StartMonitorEvents", mock.Anything, mock.Anything, mock.Anything).Return()
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{{Id: "container-id", Names: []string{"/container-name1", "/container-name2"}}}, nil).Once()
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
client.On("InspectContainer", "container-id").Return(&dockerclient.ContainerInfo{Config: &dockerclient.ContainerConfig{CpuShares: 100}}, nil).Once()
assert.NoError(t, node.connectClient(client))
assert.True(t, node.IsConnected())
// Invalid lookup
assert.Nil(t, node.Container("invalid-id"))
assert.Nil(t, node.Container(""))
// Container ID lookup.
assert.NotNil(t, node.Container("container-id"))
// Container ID prefix lookup.
assert.NotNil(t, node.Container("container-"))
// Container name lookup.
assert.NotNil(t, node.Container("container-name1"))
assert.NotNil(t, node.Container("container-name2"))
// Container node/name matching.
assert.NotNil(t, node.Container("id/container-name1"))
assert.NotNil(t, node.Container("id/container-name2"))
client.Mock.AssertExpectations(t)
}
func TestCreateContainer(t *testing.T) {
var (
config = &dockerclient.ContainerConfig{