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