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 }