github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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/juju/names.v2" 13 "gopkg.in/mgo.v2/txn" 14 15 "github.com/juju/juju/core/leadership" 16 corelease "github.com/juju/juju/core/lease" 17 "github.com/juju/juju/state/workers" 18 ) 19 20 func removeLeadershipSettingsOp(applicationId string) txn.Op { 21 return removeSettingsOp(settingsC, leadershipSettingsKey(applicationId)) 22 } 23 24 func leadershipSettingsKey(applicationId string) string { 25 return fmt.Sprintf("a#%s#leader", applicationId) 26 } 27 28 // LeadershipClaimer returns a leadership.Claimer for units and services in the 29 // state's model. 30 func (st *State) LeadershipClaimer() leadership.Claimer { 31 return leadershipClaimer{st.workers.LeadershipManager()} 32 } 33 34 // LeadershipChecker returns a leadership.Checker for units and services in the 35 // state's model. 36 func (st *State) LeadershipChecker() leadership.Checker { 37 return leadershipChecker{st.workers.LeadershipManager()} 38 } 39 40 // buildTxnWithLeadership returns a transaction source that combines the supplied source 41 // with checks and asserts on the supplied token. 42 func buildTxnWithLeadership(buildTxn jujutxn.TransactionSource, token leadership.Token) jujutxn.TransactionSource { 43 return func(attempt int) ([]txn.Op, error) { 44 var prereqs []txn.Op 45 if err := token.Check(&prereqs); err != nil { 46 return nil, errors.Annotatef(err, "prerequisites failed") 47 } 48 ops, err := buildTxn(attempt) 49 if err == jujutxn.ErrNoOperations { 50 return nil, jujutxn.ErrNoOperations 51 } else if err != nil { 52 return nil, errors.Trace(err) 53 } 54 return append(prereqs, ops...), nil 55 } 56 } 57 58 // leadershipSecretary implements lease.Secretary; it checks that leases are 59 // application names, and holders are unit names. 60 type leadershipSecretary struct{} 61 62 // CheckLease is part of the lease.Secretary interface. 63 func (leadershipSecretary) CheckLease(name string) error { 64 if !names.IsValidApplication(name) { 65 return errors.NewNotValid(nil, "not an application name") 66 } 67 return nil 68 } 69 70 // CheckHolder is part of the lease.Secretary interface. 71 func (leadershipSecretary) CheckHolder(name string) error { 72 if !names.IsValidUnit(name) { 73 return errors.NewNotValid(nil, "not a unit name") 74 } 75 return nil 76 } 77 78 // CheckDuration is part of the lease.Secretary interface. 79 func (leadershipSecretary) CheckDuration(duration time.Duration) error { 80 if duration <= 0 { 81 return errors.NewNotValid(nil, "non-positive") 82 } 83 return nil 84 } 85 86 // leadershipChecker implements leadership.Checker by wrapping a LeaseManager. 87 type leadershipChecker struct { 88 manager workers.LeaseManager 89 } 90 91 // LeadershipCheck is part of the leadership.Checker interface. 92 func (m leadershipChecker) LeadershipCheck(applicationname, unitName string) leadership.Token { 93 token := m.manager.Token(applicationname, unitName) 94 return leadershipToken{ 95 applicationname: applicationname, 96 unitName: unitName, 97 token: token, 98 } 99 } 100 101 // leadershipToken implements leadership.Token by wrapping a corelease.Token. 102 type leadershipToken struct { 103 applicationname string 104 unitName string 105 token corelease.Token 106 } 107 108 // Check is part of the leadership.Token interface. 109 func (t leadershipToken) Check(out interface{}) error { 110 err := t.token.Check(out) 111 if errors.Cause(err) == corelease.ErrNotHeld { 112 return errors.Errorf("%q is not leader of %q", t.unitName, t.applicationname) 113 } 114 return errors.Trace(err) 115 } 116 117 // leadershipClaimer implements leadership.Claimer by wrappping a LeaseManager. 118 type leadershipClaimer struct { 119 manager workers.LeaseManager 120 } 121 122 // ClaimLeadership is part of the leadership.Claimer interface. 123 func (m leadershipClaimer) ClaimLeadership(applicationname, unitName string, duration time.Duration) error { 124 err := m.manager.Claim(applicationname, unitName, duration) 125 if errors.Cause(err) == corelease.ErrClaimDenied { 126 return leadership.ErrClaimDenied 127 } 128 return errors.Trace(err) 129 } 130 131 // BlockUntilLeadershipReleased is part of the leadership.Claimer interface. 132 func (m leadershipClaimer) BlockUntilLeadershipReleased(applicationname string) error { 133 err := m.manager.WaitUntilExpired(applicationname) 134 return errors.Trace(err) 135 }