github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/state/leadership/check.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package leadership
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  	"gopkg.in/mgo.v2/txn"
    10  )
    11  
    12  // check is used to deliver leadership-check requests to a manager's loop
    13  // goroutine on behalf of LeadershipCheck.
    14  type check struct {
    15  	serviceName string
    16  	unitName    string
    17  	response    chan txn.Op
    18  	abort       <-chan struct{}
    19  }
    20  
    21  // validate returns an error if any fields are invalid or missing.
    22  func (c check) validate() error {
    23  	if !names.IsValidService(c.serviceName) {
    24  		return errors.Errorf("invalid service name %q", c.serviceName)
    25  	}
    26  	if !names.IsValidUnit(c.unitName) {
    27  		return errors.Errorf("invalid unit name %q", c.unitName)
    28  	}
    29  	if c.response == nil {
    30  		return errors.New("missing response channel")
    31  	}
    32  	if c.abort == nil {
    33  		return errors.New("missing abort channel")
    34  	}
    35  	return nil
    36  }
    37  
    38  // invoke sends the check on the supplied channel, waits for a response, and
    39  // returns either a txn.Op that can be used to assert continued leadership in
    40  // the future, or an error.
    41  func (c check) invoke(ch chan<- check) (txn.Op, error) {
    42  	if err := c.validate(); err != nil {
    43  		return txn.Op{}, errors.Annotatef(err, "cannot check leadership")
    44  	}
    45  	for {
    46  		select {
    47  		case <-c.abort:
    48  			return txn.Op{}, errStopped
    49  		case ch <- c:
    50  			ch = nil
    51  		case op, ok := <-c.response:
    52  			if !ok {
    53  				return txn.Op{}, errors.Errorf("%q is not leader of %q", c.unitName, c.serviceName)
    54  			}
    55  			return op, nil
    56  		}
    57  	}
    58  }
    59  
    60  // succeed sends the supplied operation back to the originating invoke.
    61  func (c check) succeed(op txn.Op) {
    62  	select {
    63  	case <-c.abort:
    64  	case c.response <- op:
    65  	}
    66  }
    67  
    68  // fail causes the originating invoke to return an error indicating non-leadership.
    69  func (c check) fail() {
    70  	close(c.response)
    71  }