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  }