Merge pull request #572 from vieux/improve_docker_info

add strategy and filters to docker info
This commit is contained in:
Andrea Luzzardi 2015-04-03 16:35:39 -07:00
commit c101ab7548
14 changed files with 133 additions and 32 deletions

View File

@ -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()})

View File

@ -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,23 +84,24 @@ 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{
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",
// }
)

View File

@ -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,

View File

@ -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)

View File

@ -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)

View File

@ -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 {

View File

@ -10,23 +10,25 @@ 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)
}
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{},
}
}
@ -35,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
}
}
@ -57,3 +65,14 @@ 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{}
for _, filter := range filters {
names = append(names, filter.Name())
}
return names
}

View File

@ -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{}

View File

@ -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 {

View File

@ -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, ", ")
}

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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.
@ -17,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
@ -25,21 +27,37 @@ 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" { //TODO: remove this 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
}
// List returns the names of all the available strategies
func List() []string {
names := []string{}
for _, strategy := range strategies {
names = append(names, strategy.Name())
}
return names
}