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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package unitassigner
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/facade"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/state"
    14  	"github.com/juju/juju/state/watcher"
    15  )
    16  
    17  func init() {
    18  	common.RegisterStandardFacade("UnitAssigner", 1, New)
    19  }
    20  
    21  // assignerState defines the state methods this facade needs, so they can be mocked
    22  // for testing.
    23  type assignerState interface {
    24  	WatchForUnitAssignment() state.StringsWatcher
    25  	AssignStagedUnits(ids []string) ([]state.UnitAssignmentResult, error)
    26  }
    27  
    28  type statusSetter interface {
    29  	SetStatus(args params.SetStatus) (params.ErrorResults, error)
    30  }
    31  
    32  // API implements the functionality for assigning units to machines.
    33  type API struct {
    34  	st           assignerState
    35  	res          facade.Resources
    36  	statusSetter statusSetter
    37  }
    38  
    39  // New returns a new unitAssigner api instance.
    40  func New(st *state.State, res facade.Resources, _ facade.Authorizer) (*API, error) {
    41  	setter := common.NewStatusSetter(&common.UnitAgentFinder{st}, common.AuthAlways())
    42  	return &API{
    43  		st:           st,
    44  		res:          res,
    45  		statusSetter: setter,
    46  	}, nil
    47  }
    48  
    49  //  AssignUnits assigns the units with the given ids to the correct machine. The
    50  //  error results are returned in the same order as the given entities.
    51  func (a *API) AssignUnits(args params.Entities) (params.ErrorResults, error) {
    52  	result := params.ErrorResults{}
    53  
    54  	// state uses ids, but the API uses Tags, so we have to convert back and
    55  	// forth (whee!).  The list of ids is (crucially) in the same order as the
    56  	// list of tags.  This is the same order as the list of errors we return.
    57  	ids := make([]string, len(args.Entities))
    58  	for i, e := range args.Entities {
    59  		tag, err := names.ParseUnitTag(e.Tag)
    60  		if err != nil {
    61  			return result, err
    62  		}
    63  		ids[i] = tag.Id()
    64  	}
    65  
    66  	res, err := a.st.AssignStagedUnits(ids)
    67  	if err != nil {
    68  		return result, common.ServerError(err)
    69  	}
    70  
    71  	// The results come back from state in an undetermined order and do not
    72  	// include results for units that were not found, so we have to make up for
    73  	// that here.
    74  	resultMap := make(map[string]error, len(ids))
    75  	for _, r := range res {
    76  		resultMap[r.Unit] = r.Error
    77  	}
    78  
    79  	result.Results = make([]params.ErrorResult, len(args.Entities))
    80  	for i, id := range ids {
    81  		if err, ok := resultMap[id]; ok {
    82  			result.Results[i].Error = common.ServerError(err)
    83  		} else {
    84  			result.Results[i].Error =
    85  				common.ServerError(errors.NotFoundf("unit %q", args.Entities[i].Tag))
    86  		}
    87  	}
    88  
    89  	return result, nil
    90  }
    91  
    92  // WatchUnitAssignments returns a strings watcher that is notified when new unit
    93  // assignments are added to the db.
    94  func (a *API) WatchUnitAssignments() (params.StringsWatchResult, error) {
    95  	watch := a.st.WatchForUnitAssignment()
    96  	if changes, ok := <-watch.Changes(); ok {
    97  		return params.StringsWatchResult{
    98  			StringsWatcherId: a.res.Register(watch),
    99  			Changes:          changes,
   100  		}, nil
   101  	}
   102  	return params.StringsWatchResult{}, watcher.EnsureErr(watch)
   103  }
   104  
   105  // SetAgentStatus will set status for agents of Units passed in args, if one
   106  // of the args is not an Unit it will fail.
   107  func (a *API) SetAgentStatus(args params.SetStatus) (params.ErrorResults, error) {
   108  	return a.statusSetter.SetStatus(args)
   109  }