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  }