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  }