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 }