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 }