github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/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 "github.com/juju/juju/apiserver/params" 9 "github.com/juju/juju/status" 10 "github.com/juju/juju/watcher" 11 "github.com/juju/juju/worker" 12 "github.com/juju/loggo" 13 "gopkg.in/juju/names.v2" 14 ) 15 16 var logger = loggo.GetLogger("juju.worker.unitassigner") 17 18 type UnitAssigner interface { 19 AssignUnits(tags []names.UnitTag) ([]error, error) 20 WatchUnitAssignments() (watcher.StringsWatcher, error) 21 SetAgentStatus(args params.SetStatus) error 22 } 23 24 func New(ua UnitAssigner) (worker.Worker, error) { 25 return watcher.NewStringsWorker(watcher.StringsConfig{ 26 Handler: unitAssignerHandler{api: ua}, 27 }) 28 } 29 30 type unitAssignerHandler struct { 31 api UnitAssigner 32 } 33 34 func (u unitAssignerHandler) SetUp() (watcher.StringsWatcher, error) { 35 return u.api.WatchUnitAssignments() 36 } 37 38 func (u unitAssignerHandler) Handle(_ <-chan struct{}, ids []string) error { 39 logger.Tracef("Handling unit assignments: %q", ids) 40 if len(ids) == 0 { 41 return nil 42 } 43 44 units := make([]names.UnitTag, len(ids)) 45 for i, id := range ids { 46 if !names.IsValidUnit(id) { 47 return errors.Errorf("%q is not a valid unit id", id) 48 } 49 units[i] = names.NewUnitTag(id) 50 } 51 52 results, err := u.api.AssignUnits(units) 53 if err != nil { 54 return err 55 } 56 57 failures := map[string]error{} 58 59 logger.Tracef("Unit assignment results: %q", results) 60 // errors are returned in the same order as the ids given. Any errors from 61 // the assign units call must be reported as error statuses on the 62 // respective units (though the assignments will be retried). Not found 63 // errors indicate that the unit was removed before the assignment was 64 // requested, which can be safely ignored. 65 for i, err := range results { 66 if err != nil && !errors.IsNotFound(err) { 67 failures[units[i].String()] = err 68 } 69 } 70 71 if len(failures) > 0 { 72 args := params.SetStatus{ 73 Entities: make([]params.EntityStatusArgs, len(failures)), 74 } 75 76 x := 0 77 for unit, err := range failures { 78 args.Entities[x] = params.EntityStatusArgs{ 79 Tag: unit, 80 Status: status.Error.String(), 81 Info: err.Error(), 82 } 83 x++ 84 } 85 86 return u.api.SetAgentStatus(args) 87 } 88 return nil 89 } 90 91 func (unitAssignerHandler) TearDown() error { 92 return nil 93 }