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  }