github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/singular/singular.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package singular
     5  
     6  import (
     7  	"time"
     8  
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/facade"
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/core/lease"
    15  	"github.com/juju/juju/state"
    16  )
    17  
    18  func init() {
    19  	common.RegisterStandardFacade(
    20  		"Singular", 1,
    21  		func(st *state.State, _ facade.Resources, auth facade.Authorizer) (*Facade, error) {
    22  			return NewFacade(st, auth)
    23  		},
    24  	)
    25  }
    26  
    27  // Backend supplies capabilities required by a Facade.
    28  type Backend interface {
    29  
    30  	// ModelTag tells the Facade what models it should consider requests for.
    31  	ModelTag() names.ModelTag
    32  
    33  	// SingularClaimer allows the Facade to make claims.
    34  	SingularClaimer() lease.Claimer
    35  }
    36  
    37  // NewFacade returns a singular-controller API facade, backed by the supplied
    38  // state, so long as the authorizer represents a controller machine.
    39  func NewFacade(backend Backend, auth facade.Authorizer) (*Facade, error) {
    40  	if !auth.AuthModelManager() {
    41  		return nil, common.ErrPerm
    42  	}
    43  	return &Facade{
    44  		auth:    auth,
    45  		model:   backend.ModelTag(),
    46  		claimer: backend.SingularClaimer(),
    47  	}, nil
    48  }
    49  
    50  // Facade allows controller machines to request exclusive rights to administer
    51  // some specific model for a limited time.
    52  type Facade struct {
    53  	auth    facade.Authorizer
    54  	model   names.ModelTag
    55  	claimer lease.Claimer
    56  }
    57  
    58  // Wait waits for the singular-controller lease to expire for all supplied
    59  // entities. (In practice, any requests that do not refer to the connection's
    60  // model will be rejected.)
    61  func (facade *Facade) Wait(args params.Entities) (result params.ErrorResults) {
    62  	result.Results = make([]params.ErrorResult, len(args.Entities))
    63  	for i, entity := range args.Entities {
    64  		var err error
    65  		switch {
    66  		case entity.Tag != facade.model.String():
    67  			err = common.ErrPerm
    68  		default:
    69  			err = facade.claimer.WaitUntilExpired(facade.model.Id())
    70  		}
    71  		result.Results[i].Error = common.ServerError(err)
    72  	}
    73  	return result
    74  }
    75  
    76  // Claim makes the supplied singular-controller lease requests. (In practice,
    77  // any requests not for the connection's model, or not on behalf of the
    78  // connected EnvironManager machine, will be rejected.)
    79  func (facade *Facade) Claim(args params.SingularClaims) (result params.ErrorResults) {
    80  	result.Results = make([]params.ErrorResult, len(args.Claims))
    81  	for i, claim := range args.Claims {
    82  		var err error
    83  		switch {
    84  		case claim.ModelTag != facade.model.String():
    85  			err = common.ErrPerm
    86  		case claim.ControllerTag != facade.auth.GetAuthTag().String():
    87  			err = common.ErrPerm
    88  		case !allowedDuration(claim.Duration):
    89  			err = common.ErrPerm
    90  		default:
    91  			err = facade.claimer.Claim(facade.model.Id(), claim.ControllerTag, claim.Duration)
    92  		}
    93  		result.Results[i].Error = common.ServerError(err)
    94  	}
    95  	return result
    96  }
    97  
    98  // allowedDuration returns true if the supplied duration is at least one second,
    99  // and no more than one minute. (We expect to refine the lease-length times, but
   100  // these seem like reasonable bounds.)
   101  func allowedDuration(duration time.Duration) bool {
   102  	if duration < time.Second {
   103  		return false
   104  	}
   105  	return duration <= time.Minute
   106  }