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