mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #24146 from johnharris85/fix-swarm-update-auto-accept
Add comma-separated --auto-accept support.
This commit is contained in:
commit
7da11b1afd
3 changed files with 70 additions and 44 deletions
|
@ -14,10 +14,10 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultListenAddr = "0.0.0.0:2377"
|
defaultListenAddr = "0.0.0.0:2377"
|
||||||
// WORKER constant for worker name
|
|
||||||
WORKER = "WORKER"
|
worker = "WORKER"
|
||||||
// MANAGER constant for manager name
|
manager = "MANAGER"
|
||||||
MANAGER = "MANAGER"
|
none = "NONE"
|
||||||
|
|
||||||
flagAutoAccept = "auto-accept"
|
flagAutoAccept = "auto-accept"
|
||||||
flagCertExpiry = "cert-expiry"
|
flagCertExpiry = "cert-expiry"
|
||||||
|
@ -30,8 +30,8 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultPolicies = []swarm.Policy{
|
defaultPolicies = []swarm.Policy{
|
||||||
{Role: WORKER, Autoaccept: true},
|
{Role: worker, Autoaccept: true},
|
||||||
{Role: MANAGER, Autoaccept: false},
|
{Role: manager, Autoaccept: false},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -86,40 +86,33 @@ func NewListenAddrOption() NodeAddrOption {
|
||||||
|
|
||||||
// AutoAcceptOption is a value type for auto-accept policy
|
// AutoAcceptOption is a value type for auto-accept policy
|
||||||
type AutoAcceptOption struct {
|
type AutoAcceptOption struct {
|
||||||
values map[string]bool
|
values map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String prints a string representation of this option
|
// String prints a string representation of this option
|
||||||
func (o *AutoAcceptOption) String() string {
|
func (o *AutoAcceptOption) String() string {
|
||||||
keys := []string{}
|
keys := []string{}
|
||||||
for key, value := range o.values {
|
for key := range o.values {
|
||||||
keys = append(keys, fmt.Sprintf("%s=%v", strings.ToLower(key), value))
|
keys = append(keys, fmt.Sprintf("%s=true", strings.ToLower(key)))
|
||||||
}
|
}
|
||||||
return strings.Join(keys, ", ")
|
return strings.Join(keys, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets a new value on this option
|
// Set sets a new value on this option
|
||||||
func (o *AutoAcceptOption) Set(value string) error {
|
func (o *AutoAcceptOption) Set(acceptValues string) error {
|
||||||
value = strings.ToUpper(value)
|
for _, value := range strings.Split(acceptValues, ",") {
|
||||||
switch value {
|
value = strings.ToUpper(value)
|
||||||
case "", "NONE":
|
switch value {
|
||||||
if accept, ok := o.values[WORKER]; ok && accept {
|
case none, worker, manager:
|
||||||
return fmt.Errorf("value NONE is incompatible with %s", WORKER)
|
o.values[value] = struct{}{}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("must be one / combination of %s, %s; or NONE", worker, manager)
|
||||||
}
|
}
|
||||||
if accept, ok := o.values[MANAGER]; ok && accept {
|
|
||||||
return fmt.Errorf("value NONE is incompatible with %s", MANAGER)
|
|
||||||
}
|
|
||||||
o.values[WORKER] = false
|
|
||||||
o.values[MANAGER] = false
|
|
||||||
case WORKER, MANAGER:
|
|
||||||
if accept, ok := o.values[value]; ok && !accept {
|
|
||||||
return fmt.Errorf("value NONE is incompatible with %s", value)
|
|
||||||
}
|
|
||||||
o.values[value] = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("must be one of %s, %s, NONE", WORKER, MANAGER)
|
|
||||||
}
|
}
|
||||||
|
// NONE must stand alone, so if any non-NONE setting exist with it, error with conflict
|
||||||
|
if o.isPresent(none) && len(o.values) > 1 {
|
||||||
|
return fmt.Errorf("value NONE cannot be specified alongside other node types")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +126,11 @@ func (o *AutoAcceptOption) Policies(secret *string) []swarm.Policy {
|
||||||
policies := []swarm.Policy{}
|
policies := []swarm.Policy{}
|
||||||
for _, p := range defaultPolicies {
|
for _, p := range defaultPolicies {
|
||||||
if len(o.values) != 0 {
|
if len(o.values) != 0 {
|
||||||
p.Autoaccept = o.values[string(p.Role)]
|
if _, ok := o.values[string(p.Role)]; ok {
|
||||||
|
p.Autoaccept = true
|
||||||
|
} else {
|
||||||
|
p.Autoaccept = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.Secret = secret
|
p.Secret = secret
|
||||||
policies = append(policies, p)
|
policies = append(policies, p)
|
||||||
|
@ -141,9 +138,15 @@ func (o *AutoAcceptOption) Policies(secret *string) []swarm.Policy {
|
||||||
return policies
|
return policies
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isPresent returns whether the key exists in the set or not
|
||||||
|
func (o *AutoAcceptOption) isPresent(key string) bool {
|
||||||
|
_, c := o.values[key]
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// NewAutoAcceptOption returns a new auto-accept option
|
// NewAutoAcceptOption returns a new auto-accept option
|
||||||
func NewAutoAcceptOption() AutoAcceptOption {
|
func NewAutoAcceptOption() AutoAcceptOption {
|
||||||
return AutoAcceptOption{values: make(map[string]bool)}
|
return AutoAcceptOption{values: make(map[string]struct{})}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalCAOption is a Value type for parsing external CA specifications.
|
// ExternalCAOption is a Value type for parsing external CA specifications.
|
||||||
|
|
|
@ -40,35 +40,51 @@ func TestNodeAddrOptionSetInvalidFormat(t *testing.T) {
|
||||||
func TestAutoAcceptOptionSetWorker(t *testing.T) {
|
func TestAutoAcceptOptionSetWorker(t *testing.T) {
|
||||||
opt := NewAutoAcceptOption()
|
opt := NewAutoAcceptOption()
|
||||||
assert.NilError(t, opt.Set("worker"))
|
assert.NilError(t, opt.Set("worker"))
|
||||||
assert.Equal(t, opt.values[WORKER], true)
|
assert.Equal(t, opt.isPresent(worker), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoAcceptOptionSetManager(t *testing.T) {
|
func TestAutoAcceptOptionSetManager(t *testing.T) {
|
||||||
opt := NewAutoAcceptOption()
|
opt := NewAutoAcceptOption()
|
||||||
assert.NilError(t, opt.Set("manager"))
|
assert.NilError(t, opt.Set("manager"))
|
||||||
assert.Equal(t, opt.values[MANAGER], true)
|
assert.Equal(t, opt.isPresent(manager), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoAcceptOptionSetInvalid(t *testing.T) {
|
func TestAutoAcceptOptionSetInvalid(t *testing.T) {
|
||||||
opt := NewAutoAcceptOption()
|
opt := NewAutoAcceptOption()
|
||||||
assert.Error(t, opt.Set("bogus"), "must be one of")
|
assert.Error(t, opt.Set("bogus"), "must be one / combination")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoAcceptOptionSetEmpty(t *testing.T) {
|
||||||
|
opt := NewAutoAcceptOption()
|
||||||
|
assert.Error(t, opt.Set(""), "must be one / combination")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoAcceptOptionSetNone(t *testing.T) {
|
func TestAutoAcceptOptionSetNone(t *testing.T) {
|
||||||
opt := NewAutoAcceptOption()
|
opt := NewAutoAcceptOption()
|
||||||
assert.NilError(t, opt.Set("none"))
|
assert.NilError(t, opt.Set("none"))
|
||||||
assert.Equal(t, opt.values[MANAGER], false)
|
assert.Equal(t, opt.isPresent(manager), false)
|
||||||
assert.Equal(t, opt.values[WORKER], false)
|
assert.Equal(t, opt.isPresent(worker), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoAcceptOptionSetTwo(t *testing.T) {
|
||||||
|
opt := NewAutoAcceptOption()
|
||||||
|
assert.NilError(t, opt.Set("worker,manager"))
|
||||||
|
assert.Equal(t, opt.isPresent(manager), true)
|
||||||
|
assert.Equal(t, opt.isPresent(worker), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoAcceptOptionSetConflict(t *testing.T) {
|
func TestAutoAcceptOptionSetConflict(t *testing.T) {
|
||||||
opt := NewAutoAcceptOption()
|
opt := NewAutoAcceptOption()
|
||||||
assert.NilError(t, opt.Set("manager"))
|
assert.Error(t, opt.Set("none,manager"), "value NONE cannot be specified alongside other node types")
|
||||||
assert.Error(t, opt.Set("none"), "value NONE is incompatible with MANAGER")
|
|
||||||
|
|
||||||
opt = NewAutoAcceptOption()
|
opt = NewAutoAcceptOption()
|
||||||
assert.NilError(t, opt.Set("none"))
|
assert.Error(t, opt.Set("none,worker"), "value NONE cannot be specified alongside other node types")
|
||||||
assert.Error(t, opt.Set("worker"), "value NONE is incompatible with WORKER")
|
|
||||||
|
opt = NewAutoAcceptOption()
|
||||||
|
assert.Error(t, opt.Set("worker,none,manager"), "value NONE cannot be specified alongside other node types")
|
||||||
|
|
||||||
|
opt = NewAutoAcceptOption()
|
||||||
|
assert.Error(t, opt.Set("worker,manager,none"), "value NONE cannot be specified alongside other node types")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoAcceptOptionPoliciesDefault(t *testing.T) {
|
func TestAutoAcceptOptionPoliciesDefault(t *testing.T) {
|
||||||
|
@ -78,12 +94,12 @@ func TestAutoAcceptOptionPoliciesDefault(t *testing.T) {
|
||||||
policies := opt.Policies(&secret)
|
policies := opt.Policies(&secret)
|
||||||
assert.Equal(t, len(policies), 2)
|
assert.Equal(t, len(policies), 2)
|
||||||
assert.Equal(t, policies[0], swarm.Policy{
|
assert.Equal(t, policies[0], swarm.Policy{
|
||||||
Role: WORKER,
|
Role: worker,
|
||||||
Autoaccept: true,
|
Autoaccept: true,
|
||||||
Secret: &secret,
|
Secret: &secret,
|
||||||
})
|
})
|
||||||
assert.Equal(t, policies[1], swarm.Policy{
|
assert.Equal(t, policies[1], swarm.Policy{
|
||||||
Role: MANAGER,
|
Role: manager,
|
||||||
Autoaccept: false,
|
Autoaccept: false,
|
||||||
Secret: &secret,
|
Secret: &secret,
|
||||||
})
|
})
|
||||||
|
@ -98,12 +114,12 @@ func TestAutoAcceptOptionPoliciesWithManager(t *testing.T) {
|
||||||
policies := opt.Policies(&secret)
|
policies := opt.Policies(&secret)
|
||||||
assert.Equal(t, len(policies), 2)
|
assert.Equal(t, len(policies), 2)
|
||||||
assert.Equal(t, policies[0], swarm.Policy{
|
assert.Equal(t, policies[0], swarm.Policy{
|
||||||
Role: WORKER,
|
Role: worker,
|
||||||
Autoaccept: false,
|
Autoaccept: false,
|
||||||
Secret: &secret,
|
Secret: &secret,
|
||||||
})
|
})
|
||||||
assert.Equal(t, policies[1], swarm.Policy{
|
assert.Equal(t, policies[1], swarm.Policy{
|
||||||
Role: MANAGER,
|
Role: manager,
|
||||||
Autoaccept: true,
|
Autoaccept: true,
|
||||||
Secret: &secret,
|
Secret: &secret,
|
||||||
})
|
})
|
||||||
|
|
|
@ -17,7 +17,7 @@ Usage: docker swarm init [OPTIONS]
|
||||||
Initialize a Swarm
|
Initialize a Swarm
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--auto-accept value Auto acceptance policy (worker, manager or none)
|
--auto-accept value Auto acceptance policy (default worker)
|
||||||
--cert-expiry duration Validity period for node certificates (default 2160h0m0s)
|
--cert-expiry duration Validity period for node certificates (default 2160h0m0s)
|
||||||
--dispatcher-heartbeat duration Dispatcher heartbeat period (default 5s)
|
--dispatcher-heartbeat duration Dispatcher heartbeat period (default 5s)
|
||||||
--external-ca value Specifications of one or more certificate signing endpoints
|
--external-ca value Specifications of one or more certificate signing endpoints
|
||||||
|
@ -66,6 +66,13 @@ For example, the following initializes a cluster with auto-acceptance of workers
|
||||||
$ docker swarm init --listen-addr 192.168.99.121:2377 --auto-accept worker
|
$ docker swarm init --listen-addr 192.168.99.121:2377 --auto-accept worker
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It is possible to pass a comma-separated list of node types. The following initializes a cluster
|
||||||
|
with auto-acceptance of both `worker` and `manager` nodes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker swarm init --listen-addr 192.168.99.121:2377 --auto-accept worker,manager
|
||||||
|
```
|
||||||
|
|
||||||
### `--cert-expiry`
|
### `--cert-expiry`
|
||||||
|
|
||||||
This flag sets the validity period for node certificates.
|
This flag sets the validity period for node certificates.
|
||||||
|
|
Loading…
Reference in a new issue