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 }