github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/apiserver/servicescaler/facade.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package servicescaler 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/juju/apiserver/common" 9 "github.com/juju/juju/apiserver/params" 10 "github.com/juju/juju/state" 11 "github.com/juju/juju/state/watcher" 12 "github.com/juju/names" 13 ) 14 15 // Backend exposes functionality required by Facade. 16 type Backend interface { 17 18 // WatchScaledServices returns a watcher that sends service ids 19 // that might not have enough units. 20 WatchScaledServices() state.StringsWatcher 21 22 // RescaleService ensures that the named service has at least its 23 // configured minimum unit count. 24 RescaleService(name string) error 25 } 26 27 // Facade allows model-manager clients to watch and rescale services. 28 type Facade struct { 29 backend Backend 30 resources *common.Resources 31 } 32 33 // NewFacade creates a new authorized Facade. 34 func NewFacade(backend Backend, res *common.Resources, auth common.Authorizer) (*Facade, error) { 35 if !auth.AuthModelManager() { 36 return nil, common.ErrPerm 37 } 38 return &Facade{ 39 backend: backend, 40 resources: res, 41 }, nil 42 } 43 44 // Watch returns a watcher that sends the names of services whose 45 // unit count may be below their configured minimum. 46 func (facade *Facade) Watch() (params.StringsWatchResult, error) { 47 watch := facade.backend.WatchScaledServices() 48 if changes, ok := <-watch.Changes(); ok { 49 id := facade.resources.Register(watch) 50 return params.StringsWatchResult{ 51 StringsWatcherId: id, 52 Changes: changes, 53 }, nil 54 } 55 return params.StringsWatchResult{}, watcher.EnsureErr(watch) 56 } 57 58 // Rescale causes any supplied services to be scaled up to their 59 // minimum size. 60 func (facade *Facade) Rescale(args params.Entities) params.ErrorResults { 61 result := params.ErrorResults{ 62 Results: make([]params.ErrorResult, len(args.Entities)), 63 } 64 for i, entity := range args.Entities { 65 err := facade.rescaleOne(entity.Tag) 66 result.Results[i].Error = common.ServerError(err) 67 } 68 return result 69 } 70 71 // rescaleOne scales up the supplied service, if necessary; or returns a 72 // suitable error. 73 func (facade *Facade) rescaleOne(tagString string) error { 74 tag, err := names.ParseTag(tagString) 75 if err != nil { 76 return errors.Trace(err) 77 } 78 serviceTag, ok := tag.(names.ServiceTag) 79 if !ok { 80 return common.ErrPerm 81 } 82 return facade.backend.RescaleService(serviceTag.Id()) 83 }