1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #32449 from aaronlehmann/cluster-locking

cluster: Allow reentrant calls to methods during shutdown
This commit is contained in:
Tõnis Tiigi 2017-04-12 18:58:12 -07:00 committed by GitHub
commit 01c80435c6
3 changed files with 17 additions and 11 deletions

View file

@ -334,8 +334,9 @@ func (c *Cluster) Cleanup() {
c.mu.Unlock() c.mu.Unlock()
return return
} }
defer c.mu.Unlock()
state := c.currentNodeState() state := c.currentNodeState()
c.mu.Unlock()
if state.IsActiveManager() { if state.IsActiveManager() {
active, reachable, unreachable, err := managerStats(state.controlClient, state.NodeID()) active, reachable, unreachable, err := managerStats(state.controlClient, state.NodeID())
if err == nil { if err == nil {
@ -345,11 +346,15 @@ func (c *Cluster) Cleanup() {
} }
} }
} }
if err := node.Stop(); err != nil { if err := node.Stop(); err != nil {
logrus.Errorf("failed to shut down cluster node: %v", err) logrus.Errorf("failed to shut down cluster node: %v", err)
signal.DumpStacks("") signal.DumpStacks("")
} }
c.mu.Lock()
c.nr = nil c.nr = nil
c.mu.Unlock()
} }
func managerStats(client swarmapi.ControlClient, currentNodeID string) (current bool, reachable int, unreachable int, err error) { func managerStats(client swarmapi.ControlClient, currentNodeID string) (current bool, reachable int, unreachable int, err error) {

View file

@ -210,11 +210,10 @@ func (n *nodeRunner) Stop() error {
n.stopping = true n.stopping = true
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel() defer cancel()
n.mu.Unlock()
if err := n.swarmNode.Stop(ctx); err != nil && !strings.Contains(err.Error(), "context canceled") { if err := n.swarmNode.Stop(ctx); err != nil && !strings.Contains(err.Error(), "context canceled") {
n.mu.Unlock()
return err return err
} }
n.mu.Unlock()
<-n.done <-n.done
return nil return nil
} }

View file

@ -25,19 +25,20 @@ import (
func (c *Cluster) Init(req types.InitRequest) (string, error) { func (c *Cluster) Init(req types.InitRequest) (string, error) {
c.controlMutex.Lock() c.controlMutex.Lock()
defer c.controlMutex.Unlock() defer c.controlMutex.Unlock()
c.mu.Lock()
if c.nr != nil { if c.nr != nil {
if req.ForceNewCluster { if req.ForceNewCluster {
// Take c.mu temporarily to wait for presently running
// API handlers to finish before shutting down the node.
c.mu.Lock()
c.mu.Unlock()
if err := c.nr.Stop(); err != nil { if err := c.nr.Stop(); err != nil {
c.mu.Unlock()
return "", err return "", err
} }
} else { } else {
c.mu.Unlock()
return "", errSwarmExists return "", errSwarmExists
} }
} }
c.mu.Unlock()
if err := validateAndSanitizeInitRequest(&req); err != nil { if err := validateAndSanitizeInitRequest(&req); err != nil {
return "", apierrors.NewBadRequestError(err) return "", apierrors.NewBadRequestError(err)
@ -325,9 +326,10 @@ func (c *Cluster) Leave(force bool) error {
state := c.currentNodeState() state := c.currentNodeState()
c.mu.Unlock()
if errors.Cause(state.err) == errSwarmLocked && !force { if errors.Cause(state.err) == errSwarmLocked && !force {
// leave a locked swarm without --force is not allowed // leave a locked swarm without --force is not allowed
c.mu.Unlock()
return errors.New("Swarm is encrypted and locked. Please unlock it first or use `--force` to ignore this message.") return errors.New("Swarm is encrypted and locked. Please unlock it first or use `--force` to ignore this message.")
} }
@ -339,7 +341,6 @@ func (c *Cluster) Leave(force bool) error {
if active && removingManagerCausesLossOfQuorum(reachable, unreachable) { if active && removingManagerCausesLossOfQuorum(reachable, unreachable) {
if isLastManager(reachable, unreachable) { if isLastManager(reachable, unreachable) {
msg += "Removing the last manager erases all current state of the swarm. Use `--force` to ignore this message. " msg += "Removing the last manager erases all current state of the swarm. Use `--force` to ignore this message. "
c.mu.Unlock()
return errors.New(msg) return errors.New(msg)
} }
msg += fmt.Sprintf("Removing this node leaves %v managers out of %v. Without a Raft quorum your swarm will be inaccessible. ", reachable-1, reachable+unreachable) msg += fmt.Sprintf("Removing this node leaves %v managers out of %v. Without a Raft quorum your swarm will be inaccessible. ", reachable-1, reachable+unreachable)
@ -350,18 +351,19 @@ func (c *Cluster) Leave(force bool) error {
} }
msg += "The only way to restore a swarm that has lost consensus is to reinitialize it with `--force-new-cluster`. Use `--force` to suppress this message." msg += "The only way to restore a swarm that has lost consensus is to reinitialize it with `--force-new-cluster`. Use `--force` to suppress this message."
c.mu.Unlock()
return errors.New(msg) return errors.New(msg)
} }
// release readers in here // release readers in here
if err := nr.Stop(); err != nil { if err := nr.Stop(); err != nil {
logrus.Errorf("failed to shut down cluster node: %v", err) logrus.Errorf("failed to shut down cluster node: %v", err)
signal.DumpStacks("") signal.DumpStacks("")
c.mu.Unlock()
return err return err
} }
c.mu.Lock()
c.nr = nil c.nr = nil
c.mu.Unlock() c.mu.Unlock()
if nodeID := state.NodeID(); nodeID != "" { if nodeID := state.NodeID(); nodeID != "" {
nodeContainers, err := c.listContainerForNode(nodeID) nodeContainers, err := c.listContainerForNode(nodeID)
if err != nil { if err != nil {