github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/singular/manifold.go (about)

     1  // Copyright 2015-2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package singular
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names/v5"
    12  	"github.com/juju/worker/v3"
    13  	"github.com/juju/worker/v3/dependency"
    14  
    15  	"github.com/juju/juju/api/base"
    16  	"github.com/juju/juju/cmd/jujud/agent/engine"
    17  )
    18  
    19  // logger is here to stop the desire of creating a package level logger.
    20  // Don't do this, instead pass one passed as manifold config.
    21  type logger interface{}
    22  
    23  var _ logger = struct{}{}
    24  
    25  // ManifoldConfig holds the information necessary to run a FlagWorker in
    26  // a dependency.Engine.
    27  type ManifoldConfig struct {
    28  	Clock         clock.Clock
    29  	APICallerName string
    30  	Duration      time.Duration
    31  	// TODO(controlleragent) - claimaint should be a ControllerAgentTag
    32  	Claimant names.Tag
    33  	Entity   names.Tag
    34  
    35  	NewFacade func(base.APICaller, names.Tag, names.Tag) (Facade, error)
    36  	NewWorker func(FlagConfig) (worker.Worker, error)
    37  }
    38  
    39  // Validate ensures the required values are set.
    40  func (config *ManifoldConfig) Validate() error {
    41  	if config.Clock == nil {
    42  		return errors.NotValidf("nil Clock")
    43  	}
    44  	if config.APICallerName == "" {
    45  		return errors.NotValidf("missing APICallerName")
    46  	}
    47  	if config.NewFacade == nil {
    48  		return errors.NotValidf("nil NewFacade")
    49  	}
    50  	if config.NewWorker == nil {
    51  		return errors.NotValidf("nil NewWorker")
    52  	}
    53  	return nil
    54  }
    55  
    56  // start is a method on ManifoldConfig because it's more readable than a closure.
    57  func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) {
    58  	if err := config.Validate(); err != nil {
    59  		return nil, errors.Trace(err)
    60  	}
    61  	var apiCaller base.APICaller
    62  	if err := context.Get(config.APICallerName, &apiCaller); err != nil {
    63  		return nil, errors.Trace(err)
    64  	}
    65  
    66  	facade, err := config.NewFacade(apiCaller, config.Claimant, config.Entity)
    67  	if err != nil {
    68  		return nil, errors.Trace(err)
    69  	}
    70  	flag, err := config.NewWorker(FlagConfig{
    71  		Clock:    config.Clock,
    72  		Facade:   facade,
    73  		Duration: config.Duration,
    74  	})
    75  	if err != nil {
    76  		return nil, errors.Trace(err)
    77  	}
    78  	return wrappedWorker{flag}, nil
    79  }
    80  
    81  // wrappedWorker wraps a flag worker, translating ErrRefresh into
    82  // dependency.ErrBounce.
    83  type wrappedWorker struct {
    84  	worker.Worker
    85  }
    86  
    87  // Wait is part of the worker.Worker interface.
    88  func (w wrappedWorker) Wait() error {
    89  	err := w.Worker.Wait()
    90  	if err == ErrRefresh {
    91  		err = dependency.ErrBounce
    92  	}
    93  	return err
    94  }
    95  
    96  // Manifold returns a dependency.Manifold that will run a FlagWorker and
    97  // expose it to clients as a engine.Flag resource.
    98  func Manifold(config ManifoldConfig) dependency.Manifold {
    99  	return dependency.Manifold{
   100  		Inputs: []string{
   101  			config.APICallerName,
   102  		},
   103  		Start: config.start,
   104  		Output: func(in worker.Worker, out interface{}) error {
   105  			if w, ok := in.(wrappedWorker); ok {
   106  				in = w.Worker
   107  			}
   108  			return engine.FlagOutput(in, out)
   109  		},
   110  	}
   111  }