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