diff --git a/cli/cli.go b/cli/cli.go index b1296a8d6c..b1b31a673e 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -104,9 +104,10 @@ func Run() { Flags: []cli.Flag{ flStore, flStrategy, flFilter, - flHosts, flHeartBeat, flOverCommit, + flHosts, flTLS, flTLSCaCert, flTLSCert, flTLSKey, flTLSVerify, - flEnableCors}, + flEnableCors, + flCluster, flClusterOpt}, Action: manage, }, { diff --git a/cli/flags.go b/cli/flags.go index ece1c6ddd8..9b2485d944 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -77,11 +77,6 @@ var ( Name: "tlsverify", Usage: "use TLS and verify the remote", } - flOverCommit = cli.Float64Flag{ - Name: "overcommit, oc", - Usage: "overcommit to apply on resources", - Value: 0.05, - } flStrategy = cli.StringFlag{ Name: "strategy", Usage: "placement strategy to use [" + strings.Join(strategy.List(), ", ") + "]", @@ -99,9 +94,14 @@ var ( Value: &flFilterValue, } -// flCluster = cli.StringFlag{ -// Name: "cluster, c", -// Usage: "cluster to use [swarm, mesos]", -// Value: "swarm", -// } + flCluster = cli.StringFlag{ + Name: "cluster-driver, c", + Usage: "cluster driver to use [swarm]", + Value: "swarm", + } + flClusterOpt = cli.StringSliceFlag{ + Name: "cluster-opt", + Usage: "cluster driver options", + Value: &cli.StringSlice{}, + } ) diff --git a/cli/help.go b/cli/help.go index fb33db5ce8..6c13e4fff2 100644 --- a/cli/help.go +++ b/cli/help.go @@ -25,7 +25,8 @@ ARGUMENTS: {{printf "\t"}} * ,{{end}}{{if .Flags}} OPTIONS: {{range .Flags}}{{.}} - {{end}}{{ end }} + {{end}}{{if (eq .Name "manage")}}{{printf "\t * swarm.overcommit=0.05\tovercommit to apply on resources"}} + {{printf "\t * swarm.discovery.heartbeat=25\ttime in second between each heartbeat"}}{{end}}{{ end }} ` } diff --git a/cli/manage.go b/cli/manage.go index 62c27c2d98..080f558efb 100644 --- a/cli/manage.go +++ b/cli/manage.go @@ -6,7 +6,6 @@ import ( "fmt" "io/ioutil" "path" - "strconv" log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" @@ -120,18 +119,10 @@ func manage(c *cli.Context) { sched := scheduler.New(s, fs) - hb, err := strconv.ParseUint(c.String("heartbeat"), 0, 32) - if hb < 1 || err != nil { - log.Fatal("--heartbeat should be an unsigned integer and greater than 0") + cluster, err := swarm.NewCluster(sched, store, tlsConfig, dflag, c.StringSlice("cluster-opt")) + if err != nil { + log.Fatal(err) } - options := &cluster.Options{ - TLSConfig: tlsConfig, - OvercommitRatio: c.Float64("overcommit"), - Discovery: dflag, - Heartbeat: hb, - } - - cluster := swarm.NewCluster(sched, store, options) // see https://github.com/codegangsta/cli/issues/160 hosts := c.StringSlice("host") diff --git a/cluster/options.go b/cluster/options.go index 5c3b37ffee..c32fab39ec 100644 --- a/cluster/options.go +++ b/cluster/options.go @@ -1,11 +1,47 @@ package cluster -import "crypto/tls" +import ( + "strconv" + "strings" +) -// Options is exported -type Options struct { - TLSConfig *tls.Config - OvercommitRatio float64 - Discovery string - Heartbeat uint64 +// DriverOpts are key=values options +type DriverOpts []string + +// String returns a string from the driver options +func (do DriverOpts) String(key string) (string, bool) { + for _, opt := range do { + kv := strings.SplitN(opt, "=", 2) + if kv[0] == key { + return kv[1], true + } + } + return "", false +} + +// Int returns an int64 from the driver options +func (do DriverOpts) Int(key string) (int64, bool) { + if value, ok := do.String(key); ok { + v, _ := strconv.ParseInt(value, 0, 64) + return v, true + } + return 0, false +} + +// Uint returns an int64 from the driver options +func (do DriverOpts) Uint(key string) (uint64, bool) { + if value, ok := do.String(key); ok { + v, _ := strconv.ParseUint(value, 0, 64) + return v, true + } + return 0, false +} + +// Float returns a float64 from the driver options +func (do DriverOpts) Float(key string) (float64, bool) { + if value, ok := do.String(key); ok { + v, _ := strconv.ParseFloat(value, 64) + return v, true + } + return 0.0, false } diff --git a/cluster/options_test.go b/cluster/options_test.go new file mode 100644 index 0000000000..42146b1e26 --- /dev/null +++ b/cluster/options_test.go @@ -0,0 +1,97 @@ +package cluster + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var opts = DriverOpts{"foo1=bar", "foo2=-5", "foo3=7", "foo4=0.6"} + +func TestString(t *testing.T) { + val, ok := opts.String("foo1") + assert.True(t, ok) + assert.Equal(t, val, "bar") + + val, ok = opts.String("foo2") + assert.True(t, ok) + assert.Equal(t, val, "-5") + + val, ok = opts.String("foo3") + assert.True(t, ok) + assert.Equal(t, val, "7") + + val, ok = opts.String("foo4") + assert.True(t, ok) + assert.Equal(t, val, "0.6") + + val, ok = opts.String("invalid") + assert.False(t, ok) + assert.Equal(t, val, "") +} + +func TestInt(t *testing.T) { + val, ok := opts.Int("foo1") + assert.True(t, ok) + assert.Equal(t, val, 0) + + val, ok = opts.Int("foo2") + assert.True(t, ok) + assert.Equal(t, val, -5) + + val, ok = opts.Int("foo3") + assert.True(t, ok) + assert.Equal(t, val, 7) + + val, ok = opts.Int("foo4") + assert.True(t, ok) + assert.Equal(t, val, 0) + + val, ok = opts.Int("invalid") + assert.False(t, ok) + assert.Equal(t, val, 0) +} + +func TestUint(t *testing.T) { + val, ok := opts.Uint("foo1") + assert.True(t, ok) + assert.Equal(t, val, uint(0)) + + val, ok = opts.Uint("foo2") + assert.True(t, ok) + assert.Equal(t, val, uint(0)) + + val, ok = opts.Uint("foo3") + assert.True(t, ok) + assert.Equal(t, val, uint(7)) + + val, ok = opts.Uint("foo4") + assert.True(t, ok) + assert.Equal(t, val, uint(0)) + + val, ok = opts.Uint("invalid") + assert.False(t, ok) + assert.Equal(t, val, uint(0)) +} + +func TestFloat(t *testing.T) { + val, ok := opts.Float("foo1") + assert.True(t, ok) + assert.Equal(t, val, 0.0) + + val, ok = opts.Float("foo2") + assert.True(t, ok) + assert.Equal(t, val, -5.0) + + val, ok = opts.Float("foo3") + assert.True(t, ok) + assert.Equal(t, val, 7.0) + + val, ok = opts.Float("foo4") + assert.True(t, ok) + assert.Equal(t, val, 0.6) + + val, ok = opts.Float("invalid") + assert.False(t, ok) + assert.Equal(t, val, 0.0) +} diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index 40db12b139..259cf66b86 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -1,6 +1,7 @@ package swarm import ( + "crypto/tls" "errors" "fmt" "io" @@ -26,24 +27,38 @@ type Cluster struct { eventHandler cluster.EventHandler engines map[string]*cluster.Engine scheduler *scheduler.Scheduler - options *cluster.Options store *state.Store + + overcommitRatio float64 + discovery string + heartbeat uint64 + TLSConfig *tls.Config } // NewCluster is exported -func NewCluster(scheduler *scheduler.Scheduler, store *state.Store, options *cluster.Options) cluster.Cluster { +func NewCluster(scheduler *scheduler.Scheduler, store *state.Store, TLSConfig *tls.Config, dflag string, options cluster.DriverOpts) (cluster.Cluster, error) { log.WithFields(log.Fields{"name": "swarm"}).Debug("Initializing cluster") cluster := &Cluster{ - engines: make(map[string]*cluster.Engine), - scheduler: scheduler, - options: options, - store: store, + engines: make(map[string]*cluster.Engine), + scheduler: scheduler, + store: store, + overcommitRatio: 0.05, + discovery: dflag, + TLSConfig: TLSConfig, + } + + if val, ok := options.Float("swarm.overcommit"); ok { + cluster.overcommitRatio = val + } + + if cluster.heartbeat, _ = options.Uint("swarm.discovery.heartbeat"); cluster.heartbeat < 1 { + return nil, errors.New("heartbeat should be an unsigned integer and greater than 0") } // get the list of entries from the discovery service go func() { - d, err := discovery.New(options.Discovery, options.Heartbeat) + d, err := discovery.New(cluster.discovery, cluster.heartbeat) if err != nil { log.Fatal(err) } @@ -58,7 +73,7 @@ func NewCluster(scheduler *scheduler.Scheduler, store *state.Store, options *clu go d.Watch(cluster.newEntries) }() - return cluster + return cluster, nil } // Handle callbacks for the events @@ -151,8 +166,8 @@ func (c *Cluster) newEntries(entries []*discovery.Entry) { for _, entry := range entries { go func(m *discovery.Entry) { if !c.hasEngine(m.String()) { - engine := cluster.NewEngine(m.String(), c.options.OvercommitRatio) - if err := engine.Connect(c.options.TLSConfig); err != nil { + engine := cluster.NewEngine(m.String(), c.overcommitRatio) + if err := engine.Connect(c.TLSConfig); err != nil { log.Error(err) return } diff --git a/test/integration/helpers.bash b/test/integration/helpers.bash index 9865006b66..d183072570 100644 --- a/test/integration/helpers.bash +++ b/test/integration/helpers.bash @@ -99,7 +99,7 @@ function swarm_manage() { discovery="$@" fi - "$SWARM_BINARY" manage -H "$SWARM_HOST" --heartbeat=1 "$discovery" & + "$SWARM_BINARY" manage -H "$SWARM_HOST" --cluster-opt "swarm.discovery.heartbeat=1" "$discovery" & SWARM_PID=$! wait_until_reachable "$SWARM_HOST" retry 10 1 check_swarm_nodes