github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/jujud/agent/unit/manifolds.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package unit 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils/voyeur" 11 12 coreagent "github.com/juju/juju/agent" 13 msapi "github.com/juju/juju/api/meterstatus" 14 "github.com/juju/juju/worker" 15 "github.com/juju/juju/worker/agent" 16 "github.com/juju/juju/worker/apiaddressupdater" 17 "github.com/juju/juju/worker/apicaller" 18 "github.com/juju/juju/worker/apiconfigwatcher" 19 "github.com/juju/juju/worker/dependency" 20 "github.com/juju/juju/worker/fortress" 21 "github.com/juju/juju/worker/leadership" 22 "github.com/juju/juju/worker/logger" 23 "github.com/juju/juju/worker/logsender" 24 "github.com/juju/juju/worker/machinelock" 25 "github.com/juju/juju/worker/meterstatus" 26 "github.com/juju/juju/worker/metrics/collect" 27 "github.com/juju/juju/worker/metrics/sender" 28 "github.com/juju/juju/worker/metrics/spool" 29 "github.com/juju/juju/worker/migrationminion" 30 "github.com/juju/juju/worker/proxyupdater" 31 "github.com/juju/juju/worker/retrystrategy" 32 "github.com/juju/juju/worker/uniter" 33 "github.com/juju/juju/worker/upgrader" 34 ) 35 36 // ManifoldsConfig allows specialisation of the result of Manifolds. 37 type ManifoldsConfig struct { 38 39 // Agent contains the agent that will be wrapped and made available to 40 // its dependencies via a dependency.Engine. 41 Agent coreagent.Agent 42 43 // LogSource will be read from by the logsender component. 44 LogSource logsender.LogRecordCh 45 46 // LeadershipGuarantee controls the behaviour of the leadership tracker. 47 LeadershipGuarantee time.Duration 48 49 // AgentConfigChanged is set whenever the unit agent's config 50 // is updated. 51 AgentConfigChanged *voyeur.Value 52 } 53 54 // Manifolds returns a set of co-configured manifolds covering the various 55 // responsibilities of a standalone unit agent. It also accepts the logSource 56 // argument because we haven't figured out how to thread all the logging bits 57 // through a dependency engine yet. 58 // 59 // Thou Shalt Not Use String Literals In This Function. Or Else. 60 func Manifolds(config ManifoldsConfig) dependency.Manifolds { 61 62 // connectFilter exists to let us retry api connections immediately 63 // on password change, rather than causing the dependency engine to 64 // wait for a while. 65 connectFilter := func(err error) error { 66 cause := errors.Cause(err) 67 if cause == apicaller.ErrChangedPassword { 68 return dependency.ErrBounce 69 } else if cause == apicaller.ErrConnectImpossible { 70 return worker.ErrTerminateAgent 71 } 72 return err 73 } 74 75 return dependency.Manifolds{ 76 77 // The agent manifold references the enclosing agent, and is the 78 // foundation stone on which most other manifolds ultimately depend. 79 // (Currently, that is "all manifolds", but consider a shared clock.) 80 agentName: agent.Manifold(config.Agent), 81 82 // The machine lock manifold is a thin concurrent wrapper around an 83 // FSLock in an agreed location. We expect it to be replaced with an 84 // in-memory lock when the unit agent moves into the machine agent. 85 machineLockName: machinelock.Manifold(machinelock.ManifoldConfig{ 86 AgentName: agentName, 87 }), 88 89 // The api-config-watcher manifold monitors the API server 90 // addresses in the agent config and bounces when they 91 // change. It's required as part of model migrations. 92 apiConfigWatcherName: apiconfigwatcher.Manifold(apiconfigwatcher.ManifoldConfig{ 93 AgentName: agentName, 94 AgentConfigChanged: config.AgentConfigChanged, 95 }), 96 97 // The api caller is a thin concurrent wrapper around a connection 98 // to some API server. It's used by many other manifolds, which all 99 // select their own desired facades. It will be interesting to see 100 // how this works when we consolidate the agents; might be best to 101 // handle the auth changes server-side..? 102 apiCallerName: apicaller.Manifold(apicaller.ManifoldConfig{ 103 AgentName: agentName, 104 APIConfigWatcherName: apiConfigWatcherName, 105 APIOpen: apicaller.APIOpen, 106 NewConnection: apicaller.ScaryConnect, 107 Filter: connectFilter, 108 }), 109 110 // The log sender is a leaf worker that sends log messages to some 111 // API server, when configured so to do. We should only need one of 112 // these in a consolidated agent. 113 logSenderName: logsender.Manifold(logsender.ManifoldConfig{ 114 APICallerName: apiCallerName, 115 LogSource: config.LogSource, 116 }), 117 118 // The upgrader is a leaf worker that returns a specific error type 119 // recognised by the unit agent, causing other workers to be stopped 120 // and the agent to be restarted running the new tools. We should only 121 // need one of these in a consolidated agent, but we'll need to be 122 // careful about behavioural differences, and interactions with the 123 // upgradesteps worker. 124 upgraderName: upgrader.Manifold(upgrader.ManifoldConfig{ 125 AgentName: agentName, 126 APICallerName: apiCallerName, 127 }), 128 129 migrationFortressName: fortress.Manifold(), 130 131 // The migration minion handles the agent side aspects of model migrations. 132 migrationMinionName: migrationminion.Manifold(migrationminion.ManifoldConfig{ 133 AgentName: agentName, 134 APICallerName: apiCallerName, 135 FortressName: migrationFortressName, 136 137 NewFacade: migrationminion.NewFacade, 138 NewWorker: migrationminion.NewWorker, 139 }), 140 141 // The logging config updater is a leaf worker that indirectly 142 // controls the messages sent via the log sender according to 143 // changes in environment config. We should only need one of 144 // these in a consolidated agent. 145 loggingConfigUpdaterName: logger.Manifold(logger.ManifoldConfig{ 146 AgentName: agentName, 147 APICallerName: apiCallerName, 148 }), 149 150 // The api address updater is a leaf worker that rewrites agent config 151 // as the controller addresses change. We should only need one of 152 // these in a consolidated agent. 153 apiAddressUpdaterName: apiaddressupdater.Manifold(apiaddressupdater.ManifoldConfig{ 154 AgentName: agentName, 155 APICallerName: apiCallerName, 156 }), 157 158 // The proxy config updater is a leaf worker that sets http/https/apt/etc 159 // proxy settings. 160 // TODO(fwereade): timing of this is suspicious. There was superstitious 161 // code trying to run this early; if that ever helped, it was only by 162 // coincidence. Probably we ought to be making components that might 163 // need proxy config into explicit dependencies of the proxy updater... 164 proxyConfigUpdaterName: proxyupdater.Manifold(proxyupdater.ManifoldConfig{ 165 APICallerName: apiCallerName, 166 }), 167 168 // The charmdir resource coordinates whether the charm directory is 169 // available or not; after 'start' hook and before 'stop' hook 170 // executes, and not during upgrades. 171 charmDirName: fortress.Manifold(), 172 173 // The leadership tracker attempts to secure and retain leadership of 174 // the unit's service, and is consulted on such matters by the 175 // uniter. As it stannds today, we'll need one per unit in a 176 // consolidated agent. 177 leadershipTrackerName: leadership.Manifold(leadership.ManifoldConfig{ 178 AgentName: agentName, 179 APICallerName: apiCallerName, 180 LeadershipGuarantee: config.LeadershipGuarantee, 181 }), 182 183 // HookRetryStrategy uses a retrystrategy worker to get a 184 // retry strategy that will be used by the uniter to run its hooks. 185 hookRetryStrategyName: retrystrategy.Manifold(retrystrategy.ManifoldConfig{ 186 AgentName: agentName, 187 APICallerName: apiCallerName, 188 NewFacade: retrystrategy.NewFacade, 189 NewWorker: retrystrategy.NewRetryStrategyWorker, 190 }), 191 192 // The uniter installs charms; manages the unit's presence in its 193 // relations; creates suboordinate units; runs all the hooks; sends 194 // metrics; etc etc etc. We expect to break it up further in the 195 // coming weeks, and to need one per unit in a consolidated agent 196 // (and probably one for each component broken out). 197 uniterName: uniter.Manifold(uniter.ManifoldConfig{ 198 AgentName: agentName, 199 APICallerName: apiCallerName, 200 LeadershipTrackerName: leadershipTrackerName, 201 MachineLockName: machineLockName, 202 CharmDirName: charmDirName, 203 HookRetryStrategyName: hookRetryStrategyName, 204 }), 205 206 // TODO (mattyw) should be added to machine agent. 207 metricSpoolName: spool.Manifold(spool.ManifoldConfig{ 208 AgentName: agentName, 209 }), 210 211 // The metric collect worker executes the collect-metrics hook in a 212 // restricted context that can safely run concurrently with other hooks. 213 metricCollectName: collect.Manifold(collect.ManifoldConfig{ 214 AgentName: agentName, 215 MetricSpoolName: metricSpoolName, 216 CharmDirName: charmDirName, 217 }), 218 219 // The meter status worker executes the meter-status-changed hook when it detects 220 // that the meter status has changed. 221 meterStatusName: meterstatus.Manifold(meterstatus.ManifoldConfig{ 222 AgentName: agentName, 223 APICallerName: apiCallerName, 224 MachineLockName: machineLockName, 225 NewHookRunner: meterstatus.NewHookRunner, 226 NewMeterStatusAPIClient: msapi.NewClient, 227 NewConnectedStatusWorker: meterstatus.NewConnectedStatusWorker, 228 NewIsolatedStatusWorker: meterstatus.NewIsolatedStatusWorker, 229 }), 230 231 // The metric sender worker periodically sends accumulated metrics to the controller. 232 metricSenderName: sender.Manifold(sender.ManifoldConfig{ 233 AgentName: agentName, 234 APICallerName: apiCallerName, 235 MetricSpoolName: metricSpoolName, 236 }), 237 } 238 } 239 240 const ( 241 agentName = "agent" 242 machineLockName = "machine-lock" 243 apiConfigWatcherName = "api-config-watcher" 244 apiCallerName = "api-caller" 245 logSenderName = "log-sender" 246 upgraderName = "upgrader" 247 248 migrationFortressName = "migration-fortress" 249 migrationMinionName = "migration-minion" 250 251 loggingConfigUpdaterName = "logging-config-updater" 252 proxyConfigUpdaterName = "proxy-config-updater" 253 apiAddressUpdaterName = "api-address-updater" 254 255 charmDirName = "charm-dir" 256 leadershipTrackerName = "leadership-tracker" 257 hookRetryStrategyName = "hook-retry-strategy" 258 uniterName = "uniter" 259 260 metricSpoolName = "metric-spool" 261 meterStatusName = "meter-status" 262 metricCollectName = "metric-collect" 263 metricSenderName = "metric-sender" 264 )