github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/resumer/manifold.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package resumer 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils/clock" 11 12 "github.com/juju/juju/agent" 13 apiagent "github.com/juju/juju/api/agent" 14 "github.com/juju/juju/api/base" 15 "github.com/juju/juju/cmd/jujud/agent/engine" 16 "github.com/juju/juju/state/multiwatcher" 17 "github.com/juju/juju/worker" 18 "github.com/juju/juju/worker/dependency" 19 ) 20 21 // ManifoldConfig defines the names of the manifolds on which a Manifold 22 // will depend. 23 type ManifoldConfig struct { 24 AgentName string 25 APICallerName string 26 Clock clock.Clock 27 Interval time.Duration 28 NewFacade func(base.APICaller) (Facade, error) 29 NewWorker func(Config) (worker.Worker, error) 30 } 31 32 // newWorker is an engine.AgentAPIStartFunc that draws context from the 33 // ManifoldConfig on which it is defined. 34 func (config ManifoldConfig) newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) { 35 36 // This bit should be encapsulated in another manifold 37 // satisfying jujud/agent/engine.Flag, as described in 38 // the implementation below. Shouldn't be a concern here. 39 if ok, err := isModelManager(a, apiCaller); err != nil { 40 return nil, errors.Trace(err) 41 } else if !ok { 42 // This depends on a job change triggering an agent 43 // bounce, which does happen today, but is not ideal; 44 // another reason to use a flag. 45 return nil, dependency.ErrMissing 46 } 47 48 // Get the API facade. 49 if config.NewFacade == nil { 50 logger.Errorf("nil NewFacade not valid, uninstalling") 51 return nil, dependency.ErrUninstall 52 } 53 facade, err := config.NewFacade(apiCaller) 54 if err != nil { 55 return nil, errors.Trace(err) 56 } 57 58 // Start the worker. 59 if config.NewWorker == nil { 60 logger.Errorf("nil NewWorker not valid, uninstalling") 61 return nil, dependency.ErrUninstall 62 } 63 worker, err := config.NewWorker(Config{ 64 Facade: facade, 65 Clock: config.Clock, 66 Interval: config.Interval, 67 }) 68 if err != nil { 69 return nil, errors.Trace(err) 70 } 71 return worker, nil 72 } 73 74 // Manifold returns a dependency manifold that runs a resumer worker, 75 // using the resources named or defined in the supplied config. 76 func Manifold(config ManifoldConfig) dependency.Manifold { 77 aaConfig := engine.AgentAPIManifoldConfig{ 78 AgentName: config.AgentName, 79 APICallerName: config.APICallerName, 80 } 81 return engine.AgentAPIManifold(aaConfig, config.newWorker) 82 } 83 84 // isModelManager returns whether the agent has JobManageModel, 85 // or an error. 86 func isModelManager(a agent.Agent, apiCaller base.APICaller) (bool, error) { 87 agentFacade := apiagent.NewState(apiCaller) 88 entity, err := agentFacade.Entity(a.CurrentConfig().Tag()) 89 if err != nil { 90 return false, errors.Trace(err) 91 } 92 for _, job := range entity.Jobs() { 93 if job == multiwatcher.JobManageModel { 94 return true, nil 95 } 96 } 97 return false, nil 98 }