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  }