github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/state/leadership.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 jujutxn "github.com/juju/txn" 12 "gopkg.in/mgo.v2/txn" 13 14 "github.com/juju/juju/core/leadership" 15 "github.com/juju/juju/core/lease" 16 ) 17 18 func removeLeadershipSettingsOp(applicationId string) txn.Op { 19 return removeSettingsOp(settingsC, leadershipSettingsKey(applicationId)) 20 } 21 22 func leadershipSettingsKey(applicationId string) string { 23 return fmt.Sprintf("a#%s#leader", applicationId) 24 } 25 26 // LeadershipClaimer returns a leadership.Claimer for units and applications in the 27 // state's model. 28 func (st *State) LeadershipClaimer() leadership.Claimer { 29 return leadershipClaimer{ 30 lazyLeaseClaimer{func() (lease.Claimer, error) { 31 manager := st.workers.leadershipManager() 32 return manager.Claimer(applicationLeadershipNamespace, st.modelUUID()) 33 }}, 34 } 35 } 36 37 // LeadershipChecker returns a leadership.Checker for units and applications in the 38 // state's model. 39 func (st *State) LeadershipChecker() leadership.Checker { 40 return leadershipChecker{ 41 lazyLeaseChecker{func() (lease.Checker, error) { 42 manager := st.workers.leadershipManager() 43 return manager.Checker(applicationLeadershipNamespace, st.modelUUID()) 44 }}, 45 } 46 } 47 48 // buildTxnWithLeadership returns a transaction source that combines the supplied source 49 // with checks and asserts on the supplied token. 50 func buildTxnWithLeadership(buildTxn jujutxn.TransactionSource, token leadership.Token) jujutxn.TransactionSource { 51 return func(attempt int) ([]txn.Op, error) { 52 var prereqs []txn.Op 53 if err := token.Check(attempt, &prereqs); err != nil { 54 return nil, errors.Annotatef(err, "prerequisites failed") 55 } 56 ops, err := buildTxn(attempt) 57 if err == jujutxn.ErrNoOperations { 58 return nil, jujutxn.ErrNoOperations 59 } else if err != nil { 60 return nil, errors.Trace(err) 61 } 62 return append(prereqs, ops...), nil 63 } 64 } 65 66 // leadershipChecker implements leadership.Checker by wrapping a lease.Checker. 67 type leadershipChecker struct { 68 checker lease.Checker 69 } 70 71 // LeadershipCheck is part of the leadership.Checker interface. 72 func (m leadershipChecker) LeadershipCheck(applicationName, unitName string) leadership.Token { 73 token := m.checker.Token(applicationName, unitName) 74 return leadershipToken{ 75 applicationName: applicationName, 76 unitName: unitName, 77 token: token, 78 } 79 } 80 81 // leadershipToken implements leadership.Token by wrapping a lease.Token. 82 type leadershipToken struct { 83 applicationName string 84 unitName string 85 token lease.Token 86 } 87 88 // Check is part of the leadership.Token interface. 89 func (t leadershipToken) Check(attempt int, out interface{}) error { 90 err := t.token.Check(attempt, out) 91 if errors.Cause(err) == lease.ErrNotHeld { 92 return errors.Errorf("%q is not leader of %q", t.unitName, t.applicationName) 93 } 94 return errors.Trace(err) 95 } 96 97 // leadershipClaimer implements leadership.Claimer by wrapping a lease.Claimer. 98 type leadershipClaimer struct { 99 claimer lease.Claimer 100 } 101 102 // ClaimLeadership is part of the leadership.Claimer interface. 103 func (m leadershipClaimer) ClaimLeadership(applicationname, unitName string, duration time.Duration) error { 104 err := m.claimer.Claim(applicationname, unitName, duration) 105 if errors.Cause(err) == lease.ErrClaimDenied { 106 return leadership.ErrClaimDenied 107 } 108 return errors.Trace(err) 109 } 110 111 // BlockUntilLeadershipReleased is part of the leadership.Claimer interface. 112 func (m leadershipClaimer) BlockUntilLeadershipReleased(applicationname string, cancel <-chan struct{}) error { 113 err := m.claimer.WaitUntilExpired(applicationname, cancel) 114 if errors.Cause(err) == lease.ErrWaitCancelled { 115 return leadership.ErrBlockCancelled 116 } 117 return errors.Trace(err) 118 }