From 20ec7a889efc54600a3c87ecc3b88284a022624d Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 3 Apr 2015 15:56:26 -0700 Subject: [PATCH 1/3] add strategy and filters to docker info Signed-off-by: Victor Vieux --- cluster/swarm/cluster.go | 6 +++++- scheduler/filter/affinity.go | 5 +++++ scheduler/filter/constraint.go | 5 +++++ scheduler/filter/dependency.go | 5 +++++ scheduler/filter/filter.go | 2 ++ scheduler/filter/health.go | 5 +++++ scheduler/filter/port.go | 5 +++++ scheduler/scheduler.go | 16 ++++++++++++++++ scheduler/strategy/binpack.go | 5 +++++ scheduler/strategy/random.go | 5 +++++ scheduler/strategy/spread.go | 5 +++++ scheduler/strategy/strategy.go | 2 ++ 12 files changed, 65 insertions(+), 1 deletion(-) diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index 244f25076f..5d04edf045 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -268,7 +268,11 @@ func (c *Cluster) listNodes() []cluster.Node { // Info is exported func (c *Cluster) Info() [][2]string { - info := [][2]string{{"\bNodes", fmt.Sprintf("%d", len(c.nodes))}} + info := [][2]string{ + {"\bStrategy", c.scheduler.Strategy()}, + {"\bFilters", c.scheduler.Filters()}, + {"\bNodes", fmt.Sprintf("%d", len(c.nodes))}, + } for _, node := range c.nodes { info = append(info, [2]string{node.Name(), node.Addr()}) diff --git a/scheduler/filter/affinity.go b/scheduler/filter/affinity.go index b0557962aa..ba0bd7d0e0 100644 --- a/scheduler/filter/affinity.go +++ b/scheduler/filter/affinity.go @@ -13,6 +13,11 @@ import ( type AffinityFilter struct { } +// Name returns the name of the filter +func (f *AffinityFilter) Name() string { + return "affinity" +} + // Filter is exported func (f *AffinityFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) { affinities, err := parseExprs("affinity", config.Env) diff --git a/scheduler/filter/constraint.go b/scheduler/filter/constraint.go index 160a642d76..5992123dfb 100644 --- a/scheduler/filter/constraint.go +++ b/scheduler/filter/constraint.go @@ -12,6 +12,11 @@ import ( type ConstraintFilter struct { } +// Name returns the name of the filter +func (f *ConstraintFilter) Name() string { + return "constraint" +} + // Filter is exported func (f *ConstraintFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) { constraints, err := parseExprs("constraint", config.Env) diff --git a/scheduler/filter/dependency.go b/scheduler/filter/dependency.go index 77db704f7f..3bd0113d2d 100644 --- a/scheduler/filter/dependency.go +++ b/scheduler/filter/dependency.go @@ -12,6 +12,11 @@ import ( type DependencyFilter struct { } +// Name returns the name of the filter +func (f *DependencyFilter) Name() string { + return "dependency" +} + // Filter is exported func (f *DependencyFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) { if len(nodes) == 0 { diff --git a/scheduler/filter/filter.go b/scheduler/filter/filter.go index 601a09dd6d..3a53bd2588 100644 --- a/scheduler/filter/filter.go +++ b/scheduler/filter/filter.go @@ -10,6 +10,8 @@ import ( // Filter is exported type Filter interface { + Name() string + // Return a subset of nodes that were accepted by the filtering policy. Filter(*dockerclient.ContainerConfig, []cluster.Node) ([]cluster.Node, error) } diff --git a/scheduler/filter/health.go b/scheduler/filter/health.go index 3e05ecbc5d..63cf35bd69 100644 --- a/scheduler/filter/health.go +++ b/scheduler/filter/health.go @@ -16,6 +16,11 @@ var ( type HealthFilter struct { } +// Name returns the name of the filter +func (f *HealthFilter) Name() string { + return "health" +} + // Filter is exported func (f *HealthFilter) Filter(_ *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) { result := []cluster.Node{} diff --git a/scheduler/filter/port.go b/scheduler/filter/port.go index cd92fa1c31..4b141fe3f6 100644 --- a/scheduler/filter/port.go +++ b/scheduler/filter/port.go @@ -13,6 +13,11 @@ import ( type PortFilter struct { } +// Name returns the name of the filter +func (p *PortFilter) Name() string { + return "port" +} + // Filter is exported func (p *PortFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) { for _, port := range config.HostConfig.PortBindings { diff --git a/scheduler/scheduler.go b/scheduler/scheduler.go index 8b148c7bb0..95ad74f74e 100644 --- a/scheduler/scheduler.go +++ b/scheduler/scheduler.go @@ -1,6 +1,7 @@ package scheduler import ( + "strings" "sync" "github.com/docker/swarm/cluster" @@ -34,3 +35,18 @@ func (s *Scheduler) SelectNodeForContainer(nodes []cluster.Node, config *dockerc return s.strategy.PlaceContainer(config, accepted) } + +// Strategy returns the strategy name +func (s *Scheduler) Strategy() string { + return s.strategy.Name() +} + +// Filters returns the list of filter's name +func (s *Scheduler) Filters() string { + filters := []string{} + for _, f := range s.filters { + filters = append(filters, f.Name()) + } + + return strings.Join(filters, ", ") +} diff --git a/scheduler/strategy/binpack.go b/scheduler/strategy/binpack.go index 3382d21a85..45c2e8257d 100644 --- a/scheduler/strategy/binpack.go +++ b/scheduler/strategy/binpack.go @@ -16,6 +16,11 @@ func (p *BinpackPlacementStrategy) Initialize() error { return nil } +// Name returns the name of the strategy +func (p *BinpackPlacementStrategy) Name() string { + return "binpack" +} + // PlaceContainer is exported func (p *BinpackPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) { weightedNodes, err := weighNodes(config, nodes) diff --git a/scheduler/strategy/random.go b/scheduler/strategy/random.go index 47e44ad5cf..3dfe4505e2 100644 --- a/scheduler/strategy/random.go +++ b/scheduler/strategy/random.go @@ -18,6 +18,11 @@ func (p *RandomPlacementStrategy) Initialize() error { return nil } +// Name returns the name of the strategy +func (p *RandomPlacementStrategy) Name() string { + return "random" +} + // PlaceContainer is exported func (p *RandomPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) { if size := len(nodes); size > 0 { diff --git a/scheduler/strategy/spread.go b/scheduler/strategy/spread.go index eb2e533b87..e7d75018c8 100644 --- a/scheduler/strategy/spread.go +++ b/scheduler/strategy/spread.go @@ -16,6 +16,11 @@ func (p *SpreadPlacementStrategy) Initialize() error { return nil } +// Name returns the name of the strategy +func (p *SpreadPlacementStrategy) Name() string { + return "spread" +} + // PlaceContainer is exported func (p *SpreadPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) { weightedNodes, err := weighNodes(config, nodes) diff --git a/scheduler/strategy/strategy.go b/scheduler/strategy/strategy.go index b5fae08049..88b34b5113 100644 --- a/scheduler/strategy/strategy.go +++ b/scheduler/strategy/strategy.go @@ -10,6 +10,8 @@ import ( // PlacementStrategy is exported type PlacementStrategy interface { + Name() string + Initialize() error // Given a container configuration and a set of nodes, select the target // node where the container should be scheduled. From 8f50c0eb7acd424a59ed4a4b42b1d2b1d73fd02c Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 3 Apr 2015 16:22:56 -0700 Subject: [PATCH 2/3] use names everywhere Signed-off-by: Victor Vieux --- flags.go | 11 ++++++---- scheduler/filter/filter.go | 38 ++++++++++++++++++++++++---------- scheduler/strategy/strategy.go | 35 ++++++++++++++++++++++--------- 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/flags.go b/flags.go index 7894390460..a8ca71916a 100644 --- a/flags.go +++ b/flags.go @@ -4,8 +4,11 @@ import ( "os" "path/filepath" "runtime" + "strings" "github.com/codegangsta/cli" + "github.com/docker/swarm/scheduler/filter" + "github.com/docker/swarm/scheduler/strategy" ) func homepath(p string) string { @@ -81,18 +84,18 @@ var ( } flStrategy = cli.StringFlag{ Name: "strategy", - Usage: "placement strategy to use [spread, binpack, random]", - Value: "spread", + Usage: "placement strategy to use [" + strings.Join(strategy.List(), ", ") + "]", + Value: strategy.List()[0], } // hack for go vet - flFilterValue = cli.StringSlice([]string{"constraint", "affinity", "health", "port", "dependency"}) + flFilterValue = cli.StringSlice(filter.List()) // DefaultFilterNumber is exported DefaultFilterNumber = len(flFilterValue) flFilter = cli.StringSliceFlag{ Name: "filter, f", - Usage: "filter to use [constraint, affinity, health, port, dependency]", + Usage: "filter to use [" + strings.Join(filter.List(), ", ") + "]", Value: &flFilterValue, } flCluster = cli.StringFlag{ diff --git a/scheduler/filter/filter.go b/scheduler/filter/filter.go index 3a53bd2588..46dd8890ae 100644 --- a/scheduler/filter/filter.go +++ b/scheduler/filter/filter.go @@ -17,18 +17,18 @@ type Filter interface { } var ( - filters map[string]Filter + filters []Filter // ErrNotSupported is exported ErrNotSupported = errors.New("filter not supported") ) func init() { - filters = map[string]Filter{ - "affinity": &AffinityFilter{}, - "health": &HealthFilter{}, - "constraint": &ConstraintFilter{}, - "port": &PortFilter{}, - "dependency": &DependencyFilter{}, + filters = []Filter{ + &AffinityFilter{}, + &HealthFilter{}, + &ConstraintFilter{}, + &PortFilter{}, + &DependencyFilter{}, } } @@ -37,10 +37,16 @@ func New(names []string) ([]Filter, error) { var selectedFilters []Filter for _, name := range names { - if filter, exists := filters[name]; exists { - log.WithField("name", name).Debug("Initializing filter") - selectedFilters = append(selectedFilters, filter) - } else { + found := false + for _, filter := range filters { + if filter.Name() == name { + log.WithField("name", name).Debug("Initializing filter") + selectedFilters = append(selectedFilters, filter) + found = true + break + } + } + if !found { return nil, ErrNotSupported } } @@ -59,3 +65,13 @@ func ApplyFilters(filters []Filter, config *dockerclient.ContainerConfig, nodes } return nodes, nil } + +func List() []string { + names := []string{} + + for _, filter := range filters { + names = append(names, filter.Name()) + } + + return names +} diff --git a/scheduler/strategy/strategy.go b/scheduler/strategy/strategy.go index 88b34b5113..61493e69a6 100644 --- a/scheduler/strategy/strategy.go +++ b/scheduler/strategy/strategy.go @@ -19,7 +19,7 @@ type PlacementStrategy interface { } var ( - strategies map[string]PlacementStrategy + strategies []PlacementStrategy // ErrNotSupported is exported ErrNotSupported = errors.New("strategy not supported") // ErrNoResourcesAvailable is exported @@ -27,21 +27,36 @@ var ( ) func init() { - strategies = map[string]PlacementStrategy{ - "binpacking": &BinpackPlacementStrategy{}, //compat - "binpack": &BinpackPlacementStrategy{}, - "spread": &SpreadPlacementStrategy{}, - "random": &RandomPlacementStrategy{}, + strategies = []PlacementStrategy{ + &SpreadPlacementStrategy{}, + &BinpackPlacementStrategy{}, + &RandomPlacementStrategy{}, } } // New is exported func New(name string) (PlacementStrategy, error) { - if strategy, exists := strategies[name]; exists { - log.WithField("name", name).Debugf("Initializing strategy") - err := strategy.Initialize() - return strategy, err + if name == "binpacking" { //compat + name = "binpack" + } + + for _, strategy := range strategies { + if strategy.Name() == name { + log.WithField("name", name).Debugf("Initializing strategy") + err := strategy.Initialize() + return strategy, err + } } return nil, ErrNotSupported } + +func List() []string { + names := []string{} + + for _, strategy := range strategies { + names = append(names, strategy.Name()) + } + + return names +} From 805b4763f46a430dd1f95a1a351abaf5d14f7147 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 3 Apr 2015 16:23:56 -0700 Subject: [PATCH 3/3] disable cluster flag Signed-off-by: Victor Vieux --- flags.go | 11 ++++++----- main.go | 2 +- scheduler/filter/filter.go | 1 + scheduler/strategy/strategy.go | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/flags.go b/flags.go index a8ca71916a..4c7da485a3 100644 --- a/flags.go +++ b/flags.go @@ -98,9 +98,10 @@ var ( Usage: "filter to use [" + strings.Join(filter.List(), ", ") + "]", Value: &flFilterValue, } - flCluster = cli.StringFlag{ - Name: "cluster, c", - Usage: "cluster to use [swarm, mesos]", - Value: "swarm", - } + +// flCluster = cli.StringFlag{ +// Name: "cluster, c", +// Usage: "cluster to use [swarm, mesos]", +// Value: "swarm", +// } ) diff --git a/main.go b/main.go index 1107ff9394..15e1de93f6 100644 --- a/main.go +++ b/main.go @@ -105,7 +105,7 @@ func main() { ShortName: "m", Usage: "manage a docker cluster", Flags: []cli.Flag{ - flStore, flCluster, + flStore, flStrategy, flFilter, flHosts, flHeartBeat, flOverCommit, flTLS, flTLSCaCert, flTLSCert, flTLSKey, flTLSVerify, diff --git a/scheduler/filter/filter.go b/scheduler/filter/filter.go index 46dd8890ae..36bd3074ac 100644 --- a/scheduler/filter/filter.go +++ b/scheduler/filter/filter.go @@ -66,6 +66,7 @@ func ApplyFilters(filters []Filter, config *dockerclient.ContainerConfig, nodes return nodes, nil } +// List returns the names of all the available filters func List() []string { names := []string{} diff --git a/scheduler/strategy/strategy.go b/scheduler/strategy/strategy.go index 61493e69a6..93afcd075c 100644 --- a/scheduler/strategy/strategy.go +++ b/scheduler/strategy/strategy.go @@ -36,7 +36,7 @@ func init() { // New is exported func New(name string) (PlacementStrategy, error) { - if name == "binpacking" { //compat + if name == "binpacking" { //TODO: remove this compat name = "binpack" } @@ -51,6 +51,7 @@ func New(name string) (PlacementStrategy, error) { return nil, ErrNotSupported } +// List returns the names of all the available strategies func List() []string { names := []string{}