use cluster.ContainerConfig

Signed-off-by: Victor Vieux <victorvieux@gmail.com>
This commit is contained in:
Victor Vieux 2015-04-24 16:55:29 -07:00
parent 3e8d48f98e
commit 6eceffacf9
24 changed files with 181 additions and 173 deletions

View File

@ -195,7 +195,7 @@ func getContainerJSON(c *context, w http.ResponseWriter, r *http.Request) {
func postContainersCreate(c *context, w http.ResponseWriter, r *http.Request) { func postContainersCreate(c *context, w http.ResponseWriter, r *http.Request) {
r.ParseForm() r.ParseForm()
var ( var (
config dockerclient.ContainerConfig config cluster.ContainerConfig
name = r.Form.Get("name") name = r.Form.Get("name")
) )

View File

@ -9,7 +9,7 @@ import (
// Cluster is exported // Cluster is exported
type Cluster interface { type Cluster interface {
// Create a container // Create a container
CreateContainer(config *dockerclient.ContainerConfig, name string) (*Container, error) CreateContainer(config *ContainerConfig, name string) (*Container, error)
// Remove a container // Remove a container
RemoveContainer(container *Container, force bool) error RemoveContainer(container *Container, force bool) error

8
cluster/config.go Normal file
View File

@ -0,0 +1,8 @@
package cluster
import "github.com/samalba/dockerclient"
// ContainerConfig is exported
type ContainerConfig struct {
dockerclient.ContainerConfig
}

View File

@ -349,7 +349,7 @@ func (e *Engine) TotalCpus() int64 {
} }
// Create a new container // Create a new container
func (e *Engine) Create(config *dockerclient.ContainerConfig, name string, pullImage bool) (*Container, error) { func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool) (*Container, error) {
var ( var (
err error err error
id string id string
@ -361,7 +361,7 @@ func (e *Engine) Create(config *dockerclient.ContainerConfig, name string, pullI
// nb of CPUs -> real CpuShares // nb of CPUs -> real CpuShares
newConfig.CpuShares = config.CpuShares * 1024 / e.Cpus newConfig.CpuShares = config.CpuShares * 1024 / e.Cpus
if id, err = client.CreateContainer(&newConfig, name); err != nil { if id, err = client.CreateContainer(&newConfig.ContainerConfig, name); err != nil {
// If the error is other than not found, abort immediately. // If the error is other than not found, abort immediately.
if err != dockerclient.ErrNotFound || !pullImage { if err != dockerclient.ErrNotFound || !pullImage {
return nil, err return nil, err
@ -371,7 +371,7 @@ func (e *Engine) Create(config *dockerclient.ContainerConfig, name string, pullI
return nil, err return nil, err
} }
// ...And try agaie. // ...And try agaie.
if id, err = client.CreateContainer(&newConfig, name); err != nil { if id, err = client.CreateContainer(&newConfig.ContainerConfig, name); err != nil {
return nil, err return nil, err
} }
} }

View File

@ -169,12 +169,12 @@ func TestEngineContainerLookup(t *testing.T) {
func TestCreateContainer(t *testing.T) { func TestCreateContainer(t *testing.T) {
var ( var (
config = &dockerclient.ContainerConfig{ config = &ContainerConfig{dockerclient.ContainerConfig{
Image: "busybox", Image: "busybox",
CpuShares: 1, CpuShares: 1,
Cmd: []string{"date"}, Cmd: []string{"date"},
Tty: false, Tty: false,
} }}
engine = NewEngine("test", 0) engine = NewEngine("test", 0)
client = mockclient.NewMockClient() client = mockclient.NewMockClient()
) )
@ -186,7 +186,7 @@ func TestCreateContainer(t *testing.T) {
assert.NoError(t, engine.connectClient(client)) assert.NoError(t, engine.connectClient(client))
assert.True(t, engine.isConnected()) assert.True(t, engine.isConnected())
mockConfig := *config mockConfig := config.ContainerConfig
mockConfig.CpuShares = config.CpuShares * 1024 / mockInfo.NCPU mockConfig.CpuShares = config.CpuShares * 1024 / mockInfo.NCPU
// Everything is ok // Everything is ok
@ -195,7 +195,7 @@ func TestCreateContainer(t *testing.T) {
client.On("CreateContainer", &mockConfig, name).Return(id, nil).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("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("ListImages").Return([]*dockerclient.Image{}, nil).Once()
client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: config}, nil).Once() client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: &config.ContainerConfig}, nil).Once()
container, err := engine.Create(config, name, false) container, err := engine.Create(config, name, false)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, container.Id, id) assert.Equal(t, container.Id, id)
@ -218,7 +218,7 @@ func TestCreateContainer(t *testing.T) {
client.On("CreateContainer", &mockConfig, name).Return(id, nil).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("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("ListImages").Return([]*dockerclient.Image{}, nil).Once()
client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: config}, nil).Once() client.On("InspectContainer", id).Return(&dockerclient.ContainerInfo{Config: &config.ContainerConfig}, nil).Once()
container, err = engine.Create(config, name, true) container, err = engine.Create(config, name, true)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, container.Id, id) assert.Equal(t, container.Id, id)

View File

@ -81,7 +81,7 @@ func (c *Cluster) RegisterEventHandler(h cluster.EventHandler) error {
} }
// CreateContainer aka schedule a brand new container into the cluster. // CreateContainer aka schedule a brand new container into the cluster.
func (c *Cluster) CreateContainer(config *dockerclient.ContainerConfig, name string) (*cluster.Container, error) { func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string) (*cluster.Container, error) {
c.scheduler.Lock() c.scheduler.Lock()
defer c.scheduler.Unlock() defer c.scheduler.Unlock()
@ -376,7 +376,7 @@ func (c *Cluster) Info() [][2]string {
// RANDOMENGINE returns a random engine. // RANDOMENGINE returns a random engine.
func (c *Cluster) RANDOMENGINE() (*cluster.Engine, error) { func (c *Cluster) RANDOMENGINE() (*cluster.Engine, error) {
n, err := c.scheduler.SelectNodeForContainer(c.listNodes(), &dockerclient.ContainerConfig{}) n, err := c.scheduler.SelectNodeForContainer(c.listNodes(), &cluster.ContainerConfig{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,8 +5,8 @@ import (
"strings" "strings"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// AffinityFilter selects only nodes based on other containers on the node. // AffinityFilter selects only nodes based on other containers on the node.
@ -19,7 +19,7 @@ func (f *AffinityFilter) Name() string {
} }
// Filter is exported // Filter is exported
func (f *AffinityFilter) Filter(config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (f *AffinityFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
affinities, err := parseExprs("affinity", config.Env) affinities, err := parseExprs("affinity", config.Env)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -62,187 +62,187 @@ func TestAffinityFilter(t *testing.T) {
) )
// Without constraints we should get the unfiltered list of nodes back. // Without constraints we should get the unfiltered list of nodes back.
result, err = f.Filter(&dockerclient.ContainerConfig{}, nodes) result, err = f.Filter(&cluster.ContainerConfig{}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, result, nodes) assert.Equal(t, result, nodes)
// Set a constraint that cannot be fulfilled and expect an error back. // Set a constraint that cannot be fulfilled and expect an error back.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container==does_not_exsits"}, Env: []string{"affinity:container==does_not_exsits"},
}, nodes) }}, nodes)
assert.Error(t, err) assert.Error(t, err)
// Set a constraint that can only be filled by a single node. // Set a constraint that can only be filled by a single node.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container==container-n0*"}, Env: []string{"affinity:container==container-n0*"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// This constraint can only be fulfilled by a subset of nodes. // This constraint can only be fulfilled by a subset of nodes.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container==container-*"}, Env: []string{"affinity:container==container-*"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.NotContains(t, result, nodes[2]) assert.NotContains(t, result, nodes[2])
// Validate by id. // Validate by id.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container==container-n0-0-id"}, Env: []string{"affinity:container==container-n0-0-id"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Validate by id. // Validate by id.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container!=container-n0-0-id"}, Env: []string{"affinity:container!=container-n0-0-id"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.NotContains(t, result, nodes[0]) assert.NotContains(t, result, nodes[0])
// Validate by id. // Validate by id.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container!=container-n0-1-id"}, Env: []string{"affinity:container!=container-n0-1-id"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.NotContains(t, result, nodes[0]) assert.NotContains(t, result, nodes[0])
// Validate by name. // Validate by name.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container==container-n1-0-name"}, Env: []string{"affinity:container==container-n1-0-name"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
// Validate by name. // Validate by name.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container!=container-n1-0-name"}, Env: []string{"affinity:container!=container-n1-0-name"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.NotContains(t, result, nodes[1]) assert.NotContains(t, result, nodes[1])
// Validate by name. // Validate by name.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:container!=container-n1-1-name"}, Env: []string{"affinity:container!=container-n1-1-name"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.NotContains(t, result, nodes[1]) assert.NotContains(t, result, nodes[1])
// Validate images by id // Validate images by id
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==image-0-id"}, Env: []string{"affinity:image==image-0-id"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Validate images by name // Validate images by name
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==image-0:tag3"}, Env: []string{"affinity:image==image-0:tag3"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
// Validate images by name // Validate images by name
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image!=image-0:tag3"}, Env: []string{"affinity:image!=image-0:tag3"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
// Validate images by name // Validate images by name
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==image-1"}, Env: []string{"affinity:image==image-1"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
// Validate images by name // Validate images by name
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image!=image-1"}, Env: []string{"affinity:image!=image-1"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
// Ensure that constraints can be chained. // Ensure that constraints can be chained.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{ Env: []string{
"affinity:container!=container-n0-1-id", "affinity:container!=container-n0-1-id",
"affinity:container!=container-n1-1-id", "affinity:container!=container-n1-1-id",
}, },
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[2]) assert.Equal(t, result[0], nodes[2])
// Ensure that constraints can be chained. // Ensure that constraints can be chained.
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{ Env: []string{
"affinity:container==container-n0-1-id", "affinity:container==container-n0-1-id",
"affinity:container==container-n1-1-id", "affinity:container==container-n1-1-id",
}, },
}, nodes) }}, nodes)
assert.Error(t, err) assert.Error(t, err)
//Tests for Soft affinity //Tests for Soft affinity
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==~image-0:tag3"}, Env: []string{"affinity:image==~image-0:tag3"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==~ima~ge-0:tag3"}, Env: []string{"affinity:image==~ima~ge-0:tag3"},
}, nodes) }}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==~image-1:tag3"}, Env: []string{"affinity:image==~image-1:tag3"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 3) assert.Len(t, result, 3)
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==~image-*"}, Env: []string{"affinity:image==~image-*"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image!=~image-*"}, Env: []string{"affinity:image!=~image-*"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[2]) assert.Equal(t, result[0], nodes[2])
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image==~/image-\\d*/"}, Env: []string{"affinity:image==~/image-\\d*/"},
}, nodes) }}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
// Not support = any more // Not support = any more
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image=image-0:tag3"}, Env: []string{"affinity:image=image-0:tag3"},
}, nodes) }}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
// Not support =! any more // Not support =! any more
result, err = f.Filter(&dockerclient.ContainerConfig{ result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{
Env: []string{"affinity:image=!image-0:tag3"}, Env: []string{"affinity:image=!image-0:tag3"},
}, nodes) }}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)

View File

@ -4,8 +4,8 @@ import (
"fmt" "fmt"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// ConstraintFilter selects only nodes that match certain labels. // ConstraintFilter selects only nodes that match certain labels.
@ -18,7 +18,7 @@ func (f *ConstraintFilter) Name() string {
} }
// Filter is exported // Filter is exported
func (f *ConstraintFilter) Filter(config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (f *ConstraintFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
constraints, err := parseExprs("constraint", config.Env) constraints, err := parseExprs("constraint", config.Env)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -3,6 +3,7 @@ package filter
import ( import (
"testing" "testing"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient" "github.com/samalba/dockerclient"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -60,54 +61,54 @@ func TestConstrainteFilter(t *testing.T) {
) )
// Without constraints we should get the unfiltered list of nodes back. // Without constraints we should get the unfiltered list of nodes back.
result, err = f.Filter(&dockerclient.ContainerConfig{}, nodes) result, err = f.Filter(&cluster.ContainerConfig{}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, result, nodes) assert.Equal(t, result, nodes)
// Set a constraint that cannot be fullfilled and expect an error back. // Set a constraint that cannot be fullfilled and expect an error back.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:does_not_exist==true"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:does_not_exist==true"}}}, nodes)
assert.Error(t, err) assert.Error(t, err)
// Set a contraint that can only be filled by a single node. // Set a contraint that can only be filled by a single node.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name==node1"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name==node1"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
// This constraint can only be fullfilled by a subset of nodes. // This constraint can only be fullfilled by a subset of nodes.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:group==1"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:group==1"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.NotContains(t, result, nodes[2]) assert.NotContains(t, result, nodes[2])
// Validate node pinning by id. // Validate node pinning by id.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:node==node-2-id"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:node==node-2-id"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[2]) assert.Equal(t, result[0], nodes[2])
// Validate node pinning by name. // Validate node pinning by name.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
// Make sure constraints are evaluated as logical ANDs. // Make sure constraints are evaluated as logical ANDs.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name==node0", "constraint:group==1"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name==node0", "constraint:group==1"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Check matching // Check matching
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region==us"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region==us"}}}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region==*us*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region==*us*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
} }
@ -121,22 +122,22 @@ func TestConstraintNotExpr(t *testing.T) {
) )
// Check not (!) expression // Check not (!) expression
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name!=node0"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name!=node0"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 3) assert.Len(t, result, 3)
// Check not does_not_exist. All should be found // Check not does_not_exist. All should be found
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name!=does_not_exist"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name!=does_not_exist"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 4) assert.Len(t, result, 4)
// Check name must not start with n // Check name must not start with n
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name!=n*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name!=n*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
// Check not with globber pattern // Check not with globber pattern
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region!=us*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region!=us*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
} }
@ -150,22 +151,22 @@ func TestConstraintRegExp(t *testing.T) {
) )
// Check with regular expression /node\d/ matches node{0..2} // Check with regular expression /node\d/ matches node{0..2}
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name==/node\d/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name==/node\d/`}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 3) assert.Len(t, result, 3)
// Check with regular expression /node\d/ matches node{0..2} // Check with regular expression /node\d/ matches node{0..2}
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name==/node[12]/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name==/node[12]/`}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
// Check with regular expression ! and regexp /node[12]/ matches node[0] and node[3] // Check with regular expression ! and regexp /node[12]/ matches node[0] and node[3]
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name!=/node[12]/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name!=/node[12]/`}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
// Validate node pinning by ! and regexp. // Validate node pinning by ! and regexp.
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:node!=/node-[01]-id/"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:node!=/node-[01]-id/"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
} }
@ -186,19 +187,19 @@ func TestFilterRegExpCaseInsensitive(t *testing.T) {
} }
// Case-sensitive, so not match // Case-sensitive, so not match
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name==/abcdef/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name==/abcdef/`}}}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
// Match with case-insensitive // Match with case-insensitive
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name==/(?i)abcdef/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name==/(?i)abcdef/`}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[3]) assert.Equal(t, result[0], nodes[3])
assert.Equal(t, result[0].Labels["name"], "aBcDeF") assert.Equal(t, result[0].Labels["name"], "aBcDeF")
// Test ! filter combined with case insensitive // Test ! filter combined with case insensitive
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name!=/(?i)abc*/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name!=/(?i)abc*/`}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 3) assert.Len(t, result, 3)
} }
@ -212,17 +213,17 @@ func TestFilterEquals(t *testing.T) {
) )
// Check == comparison // Check == comparison
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name==node0"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name==node0"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
// Test == with glob // Test == with glob
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region==us*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
// Validate node name with == // Validate node name with ==
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:node==node-1-name"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
@ -236,11 +237,11 @@ func TestUnsupportedOperators(t *testing.T) {
err error err error
) )
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name=node0"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name=node0"}}}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:name=!node0"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:name=!node0"}}}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
} }
@ -253,26 +254,26 @@ func TestFilterSoftConstraint(t *testing.T) {
err error err error
) )
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:node==~node-1-name"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:node==~node-1-name"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{`constraint:name!=~/(?i)abc*/`}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{`constraint:name!=~/(?i)abc*/`}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 4) assert.Len(t, result, 4)
// Check not with globber pattern // Check not with globber pattern
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region!=~us*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region!=~us*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 2) assert.Len(t, result, 2)
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region!=~can*"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region!=~can*"}}}, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 4) assert.Len(t, result, 4)
// Check matching // Check matching
result, err = f.Filter(&dockerclient.ContainerConfig{Env: []string{"constraint:region==~us~"}}, nodes) result, err = f.Filter(&cluster.ContainerConfig{dockerclient.ContainerConfig{Env: []string{"constraint:region==~us~"}}}, nodes)
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, result, 0) assert.Len(t, result, 0)
} }

View File

@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// DependencyFilter co-schedules dependent containers on the same node. // DependencyFilter co-schedules dependent containers on the same node.
@ -18,7 +18,7 @@ func (f *DependencyFilter) Name() string {
} }
// Filter is exported // Filter is exported
func (f *DependencyFilter) Filter(config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (f *DependencyFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
if len(nodes) == 0 { if len(nodes) == 0 {
return nodes, nil return nodes, nil
} }
@ -52,7 +52,7 @@ func (f *DependencyFilter) Filter(config *dockerclient.ContainerConfig, nodes []
} }
// Get a string representation of the dependencies found in the container config. // Get a string representation of the dependencies found in the container config.
func (f *DependencyFilter) String(config *dockerclient.ContainerConfig) string { func (f *DependencyFilter) String(config *cluster.ContainerConfig) string {
dependencies := []string{} dependencies := []string{}
for _, volume := range config.HostConfig.VolumesFrom { for _, volume := range config.HostConfig.VolumesFrom {
dependencies = append(dependencies, fmt.Sprintf("--volumes-from=%s", volume)) dependencies = append(dependencies, fmt.Sprintf("--volumes-from=%s", volume))

View File

@ -36,46 +36,46 @@ func TestDependencyFilterSimple(t *testing.T) {
} }
result []*node.Node result []*node.Node
err error err error
config *dockerclient.ContainerConfig config *cluster.ContainerConfig
) )
// No dependencies - make sure we don't filter anything out. // No dependencies - make sure we don't filter anything out.
config = &dockerclient.ContainerConfig{} config = &cluster.ContainerConfig{}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, result, nodes) assert.Equal(t, result, nodes)
// volumes-from. // volumes-from.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c0"}, VolumesFrom: []string{"c0"},
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// link. // link.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
Links: []string{"c1:foobar"}, Links: []string{"c1:foobar"},
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[1]) assert.Equal(t, result[0], nodes[1])
// net. // net.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
NetworkMode: "container:c2", NetworkMode: "container:c2",
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[2]) assert.Equal(t, result[0], nodes[2])
// net not prefixed by "container:" should be ignored. // net not prefixed by "container:" should be ignored.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
NetworkMode: "bridge", NetworkMode: "bridge",
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, result, nodes) assert.Equal(t, result, nodes)
@ -113,40 +113,40 @@ func TestDependencyFilterMulti(t *testing.T) {
} }
result []*node.Node result []*node.Node
err error err error
config *dockerclient.ContainerConfig config *cluster.ContainerConfig
) )
// Depend on c0 which is on nodes[0] // Depend on c0 which is on nodes[0]
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c0"}, VolumesFrom: []string{"c0"},
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Depend on c1 which is on nodes[0] // Depend on c1 which is on nodes[0]
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c1"}, VolumesFrom: []string{"c1"},
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Depend on c0 AND c1 which are both on nodes[0] // Depend on c0 AND c1 which are both on nodes[0]
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c0", "c1"}, VolumesFrom: []string{"c0", "c1"},
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Depend on c0 AND c2 which are on different nodes. // Depend on c0 AND c2 which are on different nodes.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c0", "c2"}, VolumesFrom: []string{"c0", "c2"},
}} }}}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.Error(t, err) assert.Error(t, err)
} }
@ -183,30 +183,30 @@ func TestDependencyFilterChaining(t *testing.T) {
} }
result []*node.Node result []*node.Node
err error err error
config *dockerclient.ContainerConfig config *cluster.ContainerConfig
) )
// Different dependencies on c0 and c1 // Different dependencies on c0 and c1
config = &dockerclient.ContainerConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{
HostConfig: dockerclient.HostConfig{ HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c0"}, VolumesFrom: []string{"c0"},
Links: []string{"c1"}, Links: []string{"c1"},
NetworkMode: "container:c1", NetworkMode: "container:c1",
}, },
} }}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, result[0], nodes[0]) assert.Equal(t, result[0], nodes[0])
// Different dependencies on c0 and c2 // Different dependencies on c0 and c2
config = &dockerclient.ContainerConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{
HostConfig: dockerclient.HostConfig{ HostConfig: dockerclient.HostConfig{
VolumesFrom: []string{"c0"}, VolumesFrom: []string{"c0"},
Links: []string{"c2"}, Links: []string{"c2"},
NetworkMode: "container:c1", NetworkMode: "container:c1",
}, },
} }}
result, err = f.Filter(config, nodes) result, err = f.Filter(config, nodes)
assert.Error(t, err) assert.Error(t, err)
} }

View File

@ -4,8 +4,8 @@ import (
"errors" "errors"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// Filter is exported // Filter is exported
@ -13,7 +13,7 @@ type Filter interface {
Name() string Name() string
// Return a subset of nodes that were accepted by the filtering policy. // Return a subset of nodes that were accepted by the filtering policy.
Filter(*dockerclient.ContainerConfig, []*node.Node) ([]*node.Node, error) Filter(*cluster.ContainerConfig, []*node.Node) ([]*node.Node, error)
} }
var ( var (
@ -54,7 +54,7 @@ func New(names []string) ([]Filter, error) {
} }
// ApplyFilters applies a set of filters in batch. // ApplyFilters applies a set of filters in batch.
func ApplyFilters(filters []Filter, config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func ApplyFilters(filters []Filter, config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
var err error var err error
for _, filter := range filters { for _, filter := range filters {

View File

@ -3,8 +3,8 @@ package filter
import ( import (
"errors" "errors"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
var ( var (
@ -22,7 +22,7 @@ func (f *HealthFilter) Name() string {
} }
// Filter is exported // Filter is exported
func (f *HealthFilter) Filter(_ *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (f *HealthFilter) Filter(_ *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
result := []*node.Node{} result := []*node.Node{}
for _, node := range nodes { for _, node := range nodes {
if node.IsHealthy { if node.IsHealthy {

View File

@ -3,6 +3,7 @@ package filter
import ( import (
"fmt" "fmt"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient" "github.com/samalba/dockerclient"
) )
@ -19,7 +20,7 @@ func (p *PortFilter) Name() string {
} }
// Filter is exported // Filter is exported
func (p *PortFilter) Filter(config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (p *PortFilter) Filter(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
if config.HostConfig.NetworkMode == "host" { if config.HostConfig.NetworkMode == "host" {
return p.filterHost(config, nodes) return p.filterHost(config, nodes)
} }
@ -27,7 +28,7 @@ func (p *PortFilter) Filter(config *dockerclient.ContainerConfig, nodes []*node.
return p.filterBridge(config, nodes) return p.filterBridge(config, nodes)
} }
func (p *PortFilter) filterHost(config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (p *PortFilter) filterHost(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
for port := range config.ExposedPorts { for port := range config.ExposedPorts {
candidates := []*node.Node{} candidates := []*node.Node{}
for _, node := range nodes { for _, node := range nodes {
@ -43,7 +44,7 @@ func (p *PortFilter) filterHost(config *dockerclient.ContainerConfig, nodes []*n
return nodes, nil return nodes, nil
} }
func (p *PortFilter) filterBridge(config *dockerclient.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) { func (p *PortFilter) filterBridge(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
for _, port := range config.HostConfig.PortBindings { for _, port := range config.HostConfig.PortBindings {
for _, binding := range port { for _, binding := range port {
candidates := []*node.Node{} candidates := []*node.Node{}

View File

@ -46,18 +46,18 @@ func TestPortFilterNoConflicts(t *testing.T) {
) )
// Request no ports. // Request no ports.
config := &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config := &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: map[string][]dockerclient.PortBinding{}, PortBindings: map[string][]dockerclient.PortBinding{},
}} }}}
// Make sure we don't filter anything out. // Make sure we don't filter anything out.
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, result, nodes) assert.Equal(t, result, nodes)
// Request port 80. // Request port 80.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("", "80"), PortBindings: makeBinding("", "80"),
}} }}}
// Since there are no other containers in the cluster, this shouldn't // Since there are no other containers in the cluster, this shouldn't
// filter anything either. // filter anything either.
@ -104,9 +104,9 @@ func TestPortFilterSimple(t *testing.T) {
assert.NoError(t, nodes[0].AddContainer(container)) assert.NoError(t, nodes[0].AddContainer(container))
// Request port 80. // Request port 80.
config := &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config := &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("", "80"), PortBindings: makeBinding("", "80"),
}} }}}
// nodes[0] should be excluded since port 80 is taken away. // nodes[0] should be excluded since port 80 is taken away.
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
@ -143,9 +143,9 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
assert.NoError(t, nodes[0].AddContainer(container)) assert.NoError(t, nodes[0].AddContainer(container))
// Request port 80 for the local interface. // Request port 80 for the local interface.
config := &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config := &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("127.0.0.1", "80"), PortBindings: makeBinding("127.0.0.1", "80"),
}} }}}
// nodes[0] should be excluded since port 80 is taken away for every // nodes[0] should be excluded since port 80 is taken away for every
// interface. // interface.
@ -158,9 +158,9 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
container = &cluster.Container{Container: dockerclient.Container{Id: "c1"}, Info: dockerclient.ContainerInfo{HostConfig: &dockerclient.HostConfig{PortBindings: makeBinding("127.0.0.1", "4242")}}} container = &cluster.Container{Container: dockerclient.Container{Id: "c1"}, Info: dockerclient.ContainerInfo{HostConfig: &dockerclient.HostConfig{PortBindings: makeBinding("127.0.0.1", "4242")}}}
assert.NoError(t, nodes[1].AddContainer(container)) assert.NoError(t, nodes[1].AddContainer(container))
// Request port 4242 on the same interface. // Request port 4242 on the same interface.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("127.0.0.1", "4242"), PortBindings: makeBinding("127.0.0.1", "4242"),
}} }}}
// nodes[1] should be excluded since port 4242 is already taken on that // nodes[1] should be excluded since port 4242 is already taken on that
// interface. // interface.
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
@ -168,27 +168,27 @@ func TestPortFilterDifferentInterfaces(t *testing.T) {
assert.NotContains(t, result, nodes[1]) assert.NotContains(t, result, nodes[1])
// Request port 4242 on every interface. // Request port 4242 on every interface.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("0.0.0.0", "4242"), PortBindings: makeBinding("0.0.0.0", "4242"),
}} }}}
// nodes[1] should still be excluded since the port is not available on the same interface. // nodes[1] should still be excluded since the port is not available on the same interface.
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotContains(t, result, nodes[1]) assert.NotContains(t, result, nodes[1])
// Request port 4242 on every interface using an alternative syntax. // Request port 4242 on every interface using an alternative syntax.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("", "4242"), PortBindings: makeBinding("", "4242"),
}} }}}
// nodes[1] should still be excluded since the port is not available on the same interface. // nodes[1] should still be excluded since the port is not available on the same interface.
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotContains(t, result, nodes[1]) assert.NotContains(t, result, nodes[1])
// Finally, request port 4242 on a different interface. // Finally, request port 4242 on a different interface.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("192.168.1.1", "4242"), PortBindings: makeBinding("192.168.1.1", "4242"),
}} }}}
// nodes[1] should be included this time since the port is available on the // nodes[1] should be included this time since the port is available on the
// other interface. // other interface.
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
@ -257,9 +257,9 @@ func TestPortFilterRandomAssignment(t *testing.T) {
assert.NoError(t, nodes[0].AddContainer(container)) assert.NoError(t, nodes[0].AddContainer(container))
// Request port 80. // Request port 80.
config := &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config := &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("", "80"), PortBindings: makeBinding("", "80"),
}} }}}
// Since port "80" has been mapped to "1234", we should be able to request "80". // Since port "80" has been mapped to "1234", we should be able to request "80".
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
@ -267,9 +267,9 @@ func TestPortFilterRandomAssignment(t *testing.T) {
assert.Equal(t, result, nodes) assert.Equal(t, result, nodes)
// However, we should not be able to request "1234" since it has been used for a random assignment. // However, we should not be able to request "1234" since it has been used for a random assignment.
config = &dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{ config = &cluster.ContainerConfig{dockerclient.ContainerConfig{HostConfig: dockerclient.HostConfig{
PortBindings: makeBinding("", "1234"), PortBindings: makeBinding("", "1234"),
}} }}}
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotContains(t, result, nodes[0]) assert.NotContains(t, result, nodes[0])
@ -315,12 +315,12 @@ func TestPortFilterForHostMode(t *testing.T) {
assert.NoError(t, nodes[0].AddContainer(container)) assert.NoError(t, nodes[0].AddContainer(container))
// Request port 80 in the host mode // Request port 80 in the host mode
config := &dockerclient.ContainerConfig{ config := &cluster.ContainerConfig{dockerclient.ContainerConfig{
ExposedPorts: map[string]struct{}{"80": {}}, ExposedPorts: map[string]struct{}{"80": {}},
HostConfig: dockerclient.HostConfig{ HostConfig: dockerclient.HostConfig{
NetworkMode: "host", NetworkMode: "host",
}, },
} }}
// nodes[0] should be excluded since port 80 is taken away // nodes[0] should be excluded since port 80 is taken away
result, err = p.Filter(config, nodes) result, err = p.Filter(config, nodes)

View File

@ -4,10 +4,10 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/filter" "github.com/docker/swarm/scheduler/filter"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/docker/swarm/scheduler/strategy" "github.com/docker/swarm/scheduler/strategy"
"github.com/samalba/dockerclient"
) )
// Scheduler is exported // Scheduler is exported
@ -27,7 +27,7 @@ func New(strategy strategy.PlacementStrategy, filters []filter.Filter) *Schedule
} }
// SelectNodeForContainer will find a nice home for our container. // SelectNodeForContainer will find a nice home for our container.
func (s *Scheduler) SelectNodeForContainer(nodes []*node.Node, config *dockerclient.ContainerConfig) (*node.Node, error) { func (s *Scheduler) SelectNodeForContainer(nodes []*node.Node, config *cluster.ContainerConfig) (*node.Node, error) {
accepted, err := filter.ApplyFilters(s.filters, config, nodes) accepted, err := filter.ApplyFilters(s.filters, config, nodes)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -3,8 +3,8 @@ package strategy
import ( import (
"sort" "sort"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// BinpackPlacementStrategy is exported // BinpackPlacementStrategy is exported
@ -22,7 +22,7 @@ func (p *BinpackPlacementStrategy) Name() string {
} }
// PlaceContainer is exported // PlaceContainer is exported
func (p *BinpackPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []*node.Node) (*node.Node, error) { func (p *BinpackPlacementStrategy) PlaceContainer(config *cluster.ContainerConfig, nodes []*node.Node) (*node.Node, error) {
weightedNodes, err := weighNodes(config, nodes) weightedNodes, err := weighNodes(config, nodes)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -22,12 +22,12 @@ func createNode(ID string, memory int64, cpus int64) *node.Node {
} }
} }
func createConfig(memory int64, cpus int64) *dockerclient.ContainerConfig { func createConfig(memory int64, cpus int64) *cluster.ContainerConfig {
return &dockerclient.ContainerConfig{Memory: memory * 1024 * 1024 * 1024, CpuShares: cpus} return &cluster.ContainerConfig{dockerclient.ContainerConfig{Memory: memory * 1024 * 1024 * 1024, CpuShares: cpus}}
} }
func createContainer(ID string, config *dockerclient.ContainerConfig) *cluster.Container { func createContainer(ID string, config *cluster.ContainerConfig) *cluster.Container {
return &cluster.Container{Container: dockerclient.Container{Id: ID}, Info: dockerclient.ContainerInfo{Config: config}} return &cluster.Container{Container: dockerclient.Container{Id: ID}, Info: dockerclient.ContainerInfo{Config: &config.ContainerConfig}}
} }
func TestPlaceEqualWeight(t *testing.T) { func TestPlaceEqualWeight(t *testing.T) {

View File

@ -5,8 +5,8 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// RandomPlacementStrategy randomly places the container into the cluster. // RandomPlacementStrategy randomly places the container into the cluster.
@ -24,7 +24,7 @@ func (p *RandomPlacementStrategy) Name() string {
} }
// PlaceContainer is exported // PlaceContainer is exported
func (p *RandomPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []*node.Node) (*node.Node, error) { func (p *RandomPlacementStrategy) PlaceContainer(config *cluster.ContainerConfig, nodes []*node.Node) (*node.Node, error) {
if size := len(nodes); size > 0 { if size := len(nodes); size > 0 {
return nodes[rand.Intn(size)], nil return nodes[rand.Intn(size)], nil
} }

View File

@ -3,8 +3,8 @@ package strategy
import ( import (
"sort" "sort"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// SpreadPlacementStrategy is exported // SpreadPlacementStrategy is exported
@ -22,7 +22,7 @@ func (p *SpreadPlacementStrategy) Name() string {
} }
// PlaceContainer is exported // PlaceContainer is exported
func (p *SpreadPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []*node.Node) (*node.Node, error) { func (p *SpreadPlacementStrategy) PlaceContainer(config *cluster.ContainerConfig, nodes []*node.Node) (*node.Node, error) {
weightedNodes, err := weighNodes(config, nodes) weightedNodes, err := weighNodes(config, nodes)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -4,8 +4,8 @@ import (
"errors" "errors"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// PlacementStrategy is exported // PlacementStrategy is exported
@ -15,7 +15,7 @@ type PlacementStrategy interface {
Initialize() error Initialize() error
// Given a container configuration and a set of nodes, select the target // Given a container configuration and a set of nodes, select the target
// node where the container should be scheduled. // node where the container should be scheduled.
PlaceContainer(config *dockerclient.ContainerConfig, nodes []*node.Node) (*node.Node, error) PlaceContainer(config *cluster.ContainerConfig, nodes []*node.Node) (*node.Node, error)
} }
var ( var (

View File

@ -1,8 +1,8 @@
package strategy package strategy
import ( import (
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/scheduler/node" "github.com/docker/swarm/scheduler/node"
"github.com/samalba/dockerclient"
) )
// WeightedNode represents a node in the cluster with a given weight, typically used for sorting // WeightedNode represents a node in the cluster with a given weight, typically used for sorting
@ -32,7 +32,7 @@ func (n weightedNodeList) Less(i, j int) bool {
return ip.Weight < jp.Weight return ip.Weight < jp.Weight
} }
func weighNodes(config *dockerclient.ContainerConfig, nodes []*node.Node) (weightedNodeList, error) { func weighNodes(config *cluster.ContainerConfig, nodes []*node.Node) (weightedNodeList, error) {
weightedNodes := weightedNodeList{} weightedNodes := weightedNodeList{}
for _, node := range nodes { for _, node := range nodes {

View File

@ -1,12 +1,10 @@
package state package state
import ( import "github.com/docker/swarm/cluster"
"github.com/samalba/dockerclient"
)
// RequestedState is exported // RequestedState is exported
type RequestedState struct { type RequestedState struct {
ID string ID string
Name string Name string
Config *dockerclient.ContainerConfig Config *cluster.ContainerConfig
} }