add images cache

Signed-off-by: Victor Vieux <vieux@docker.com>
This commit is contained in:
Victor Vieux 2015-01-15 21:51:16 +00:00
parent d54c5f8046
commit 5564894744
5 changed files with 46 additions and 28 deletions

View File

@ -18,6 +18,7 @@ func createNode(t *testing.T, ID string, containers ...dockerclient.Container) *
client := mockclient.NewMockClient()
client.On("Info").Return(mockInfo, nil)
client.On("ListContainers", true, false, "").Return(containers, nil)
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
client.On("InspectContainer", mock.Anything).Return(
&dockerclient.ContainerInfo{
Config: &dockerclient.ContainerConfig{CpuShares: 100},

View File

@ -46,6 +46,7 @@ type Node struct {
ch chan bool
containers map[string]*Container
images []*dockerclient.Image
client dockerclient.Client
eventHandler EventHandler
healthy bool
@ -84,6 +85,10 @@ func (n *Node) connectClient(client dockerclient.Client) error {
n.client = nil
return err
}
if err := n.refreshImages(); err != nil {
n.client = nil
return err
}
// Start the update loop.
go n.refreshLoop()
@ -131,6 +136,18 @@ func (n *Node) updateSpecs() error {
return nil
}
// Refresh the list of images on the node.
func (n *Node) refreshImages() error {
images, err := n.client.ListImages()
if err != nil {
return err
}
n.Lock()
n.images = images
n.Unlock()
return nil
}
// Refresh the list and status of containers running on the node.
func (n *Node) refreshContainers() error {
containers, err := n.client.ListContainers(true, false, "")
@ -237,6 +254,10 @@ func (n *Node) refreshLoop() {
err = n.refreshContainers()
}
if err == nil {
err = n.refreshImages()
}
if err != nil {
n.healthy = false
log.Errorf("[%s/%s] Flagging node as dead. Updated state failed: %v", n.ID, n.Name, err)
@ -316,23 +337,6 @@ func (n *Node) Create(config *dockerclient.ContainerConfig, name string, pullIma
return n.containers[id], nil
}
func (n *Node) ListImages() ([]string, error) {
images, err := n.client.ListImages()
if err != nil {
return nil, err
}
out := []string{}
for _, i := range images {
for _, t := range i.RepoTags {
out = append(out, t)
}
}
return out, nil
}
// Destroy and remove a container from the node.
func (n *Node) Destroy(container *Container, force bool) error {
if err := n.client.RemoveContainer(container.Id, force); err != nil {
@ -374,6 +378,12 @@ func (n *Node) Containers() []*Container {
return containers
}
func (n *Node) Images() []*dockerclient.Image {
n.RLock()
defer n.RUnlock()
return n.images
}
func (n *Node) String() string {
return fmt.Sprintf("node %s addr %s", n.ID, n.Addr)
}

View File

@ -58,6 +58,7 @@ func TestNodeCpusMemory(t *testing.T) {
client := mockclient.NewMockClient()
client.On("Info").Return(mockInfo, nil)
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil)
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
client.On("StartMonitorEvents", mock.Anything, mock.Anything).Return()
assert.NoError(t, node.connectClient(client))
@ -77,6 +78,7 @@ func TestNodeSpecs(t *testing.T) {
client := mockclient.NewMockClient()
client.On("Info").Return(mockInfo, nil)
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil)
client.On("ListImages").Return([]*dockerclient.Image{}, nil)
client.On("StartMonitorEvents", mock.Anything, mock.Anything).Return()
assert.NoError(t, node.connectClient(client))
@ -104,6 +106,7 @@ func TestNodeState(t *testing.T) {
// The client will return one container at first, then a second one will appear.
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{{Id: "one"}}, nil).Once()
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
client.On("InspectContainer", "one").Return(&dockerclient.ContainerInfo{Config: &dockerclient.ContainerConfig{CpuShares: 100}}, nil).Once()
client.On("ListContainers", true, false, fmt.Sprintf("{%q:[%q]}", "id", "two")).Return([]dockerclient.Container{{Id: "two"}}, nil).Once()
client.On("InspectContainer", "two").Return(&dockerclient.ContainerInfo{Config: &dockerclient.ContainerConfig{CpuShares: 100}}, nil).Once()
@ -147,6 +150,7 @@ func TestCreateContainer(t *testing.T) {
client.On("Info").Return(mockInfo, nil)
client.On("StartMonitorEvents", mock.Anything, mock.Anything).Return()
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil).Once()
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
assert.NoError(t, node.connectClient(client))
assert.True(t, node.IsConnected())
@ -158,6 +162,7 @@ func TestCreateContainer(t *testing.T) {
id := "id1"
client.On("CreateContainer", &mockConfig, name).Return(id, nil).Once()
client.On("ListContainers", true, false, fmt.Sprintf(`{"id":[%q]}`, id)).Return([]dockerclient.Container{{Id: id}}, nil).Once()
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: config}, nil).Once()
container, err := node.Create(config, name, false)
assert.Nil(t, err)
@ -180,6 +185,7 @@ func TestCreateContainer(t *testing.T) {
client.On("CreateContainer", &mockConfig, name).Return("", dockerclient.ErrNotFound).Once()
client.On("CreateContainer", &mockConfig, name).Return(id, nil).Once()
client.On("ListContainers", true, false, fmt.Sprintf(`{"id":[%q]}`, id)).Return([]dockerclient.Container{{Id: id}}, nil).Once()
client.On("ListImages").Return([]*dockerclient.Image{}, nil).Once()
client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: config}, nil).Once()
container, err = node.Create(config, name, true)
assert.Nil(t, err)

View File

@ -21,23 +21,24 @@ func (f *AffinityFilter) Filter(config *dockerclient.ContainerConfig, nodes []*c
switch k {
case "container":
for _, container := range node.Containers() {
// "node" label is a special case pinning a container to a specific node.
if match(v, container.Id) || match(v, container.Names[0]) {
candidates = append(candidates, node)
break
}
}
case "image":
//TODO use cache
images, err := node.ListImages()
if err != nil {
break
}
for _, image := range images {
if match(v, image) {
done:
for _, image := range node.Images() {
if match(v, image.Id) {
candidates = append(candidates, node)
break
}
for _, t := range image.RepoTags {
if match(v, t) {
candidates = append(candidates, node)
break done
}
}
}
}
}

View File

@ -14,9 +14,9 @@ func TestAffinityFilter(t *testing.T) {
var (
f = AffinityFilter{}
nodes = []*cluster.Node{
cluster.NewNode("node-0"),
cluster.NewNode("node-1"),
cluster.NewNode("node-2"),
cluster.NewNode("node-0", 0),
cluster.NewNode("node-1", 0),
cluster.NewNode("node-2", 0),
}
result []*cluster.Node
err error