github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/jujud/agent/caasoperator/manifolds.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperator 5 6 import ( 7 "time" 8 9 "github.com/juju/clock" 10 "github.com/juju/utils/voyeur" 11 "github.com/prometheus/client_golang/prometheus" 12 "gopkg.in/juju/worker.v1" 13 "gopkg.in/juju/worker.v1/dependency" 14 15 coreagent "github.com/juju/juju/agent" 16 "github.com/juju/juju/api" 17 "github.com/juju/juju/api/base" 18 caasoperatorapi "github.com/juju/juju/api/caasoperator" 19 "github.com/juju/juju/cmd/jujud/agent/engine" 20 "github.com/juju/juju/core/machinelock" 21 "github.com/juju/juju/worker/agent" 22 "github.com/juju/juju/worker/apiaddressupdater" 23 "github.com/juju/juju/worker/apicaller" 24 "github.com/juju/juju/worker/apiconfigwatcher" 25 "github.com/juju/juju/worker/caasoperator" 26 "github.com/juju/juju/worker/fortress" 27 "github.com/juju/juju/worker/gate" 28 "github.com/juju/juju/worker/logger" 29 "github.com/juju/juju/worker/logsender" 30 "github.com/juju/juju/worker/migrationflag" 31 "github.com/juju/juju/worker/migrationminion" 32 "github.com/juju/juju/worker/retrystrategy" 33 "github.com/juju/juju/worker/uniter" 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 // AgentConfigChanged is set whenever the unit agent's config 44 // is updated. 45 AgentConfigChanged *voyeur.Value 46 47 // Clock contains the clock that will be made available to manifolds. 48 Clock clock.Clock 49 50 // LogSource will be read from by the logsender component. 51 LogSource logsender.LogRecordCh 52 53 // UpdateLoggerConfig is a function that will save the specified 54 // config value as the logging config in the agent.conf file. 55 UpdateLoggerConfig func(string) error 56 57 // PrometheusRegisterer is a prometheus.Registerer that may be used 58 // by workers to register Prometheus metric collectors. 59 PrometheusRegisterer prometheus.Registerer 60 61 // LeadershipGuarantee controls the behaviour of the leadership tracker. 62 LeadershipGuarantee time.Duration 63 64 // ValidateMigration is called by the migrationminion during the 65 // migration process to check that the agent will be ok when 66 // connected to the new target controller. 67 ValidateMigration func(base.APICaller) error 68 69 // UpgradeStepsLock is passed to the upgrade steps gate to 70 // coordinate workers that shouldn't do anything until the 71 // upgrade-steps worker is done. 72 UpgradeStepsLock gate.Lock 73 74 // MachineLock is a central source for acquiring the machine lock. 75 // This is used by a number of workers to ensure serialisation of actions 76 // across the machine. 77 MachineLock machinelock.Lock 78 } 79 80 // Manifolds returns a set of co-configured manifolds covering the various 81 // responsibilities of a caasoperator agent. It also accepts the logSource 82 // argument because we haven't figured out how to thread all the logging bits 83 // through a dependency engine yet. 84 // 85 // Thou Shalt Not Use String Literals In This Function. Or Else. 86 func Manifolds(config ManifoldsConfig) dependency.Manifolds { 87 88 return dependency.Manifolds{ 89 90 // The agent manifold references the enclosing agent, and is the 91 // foundation stone on which most other manifolds ultimately depend. 92 agentName: agent.Manifold(config.Agent), 93 94 // The api-config-watcher manifold monitors the API server 95 // addresses in the agent config and bounces when they 96 // change. It's required as part of model migrations. 97 apiConfigWatcherName: apiconfigwatcher.Manifold(apiconfigwatcher.ManifoldConfig{ 98 AgentName: agentName, 99 AgentConfigChanged: config.AgentConfigChanged, 100 }), 101 102 apiCallerName: apicaller.Manifold(apicaller.ManifoldConfig{ 103 AgentName: agentName, 104 APIOpen: api.Open, 105 APIConfigWatcherName: apiConfigWatcherName, 106 NewConnection: apicaller.OnlyConnect, 107 }), 108 109 clockName: clockManifold(config.Clock), 110 111 // The log sender is a leaf worker that sends log messages to some 112 // API server, when configured so to do. We should only need one of 113 // these in a consolidated agent. 114 logSenderName: logsender.Manifold(logsender.ManifoldConfig{ 115 APICallerName: apiCallerName, 116 LogSource: config.LogSource, 117 }), 118 119 // The upgrade steps gate is used to coordinate workers which 120 // shouldn't do anything until the upgrade-steps worker has 121 // finished running any required upgrade steps. The flag of 122 // similar name is used to implement the isFullyUpgraded func 123 // that keeps upgrade concerns out of unrelated manifolds. 124 upgradeStepsGateName: gate.ManifoldEx(config.UpgradeStepsLock), 125 upgradeStepsFlagName: gate.FlagManifold(gate.FlagManifoldConfig{ 126 GateName: upgradeStepsGateName, 127 NewWorker: gate.NewFlagWorker, 128 }), 129 130 // The migration workers collaborate to run migrations; 131 // and to create a mechanism for running other workers 132 // so they can't accidentally interfere with a migration 133 // in progress. Such a manifold should (1) depend on the 134 // migration-inactive flag, to know when to start or die; 135 // and (2) occupy the migration-fortress, so as to avoid 136 // possible interference with the minion (which will not 137 // take action until it's gained sole control of the 138 // fortress). 139 migrationFortressName: ifFullyUpgraded(fortress.Manifold()), 140 migrationInactiveFlagName: migrationflag.Manifold(migrationflag.ManifoldConfig{ 141 APICallerName: apiCallerName, 142 Check: migrationflag.IsTerminal, 143 NewFacade: migrationflag.NewFacade, 144 NewWorker: migrationflag.NewWorker, 145 }), 146 migrationMinionName: migrationminion.Manifold(migrationminion.ManifoldConfig{ 147 AgentName: agentName, 148 APICallerName: apiCallerName, 149 FortressName: migrationFortressName, 150 APIOpen: api.Open, 151 ValidateMigration: config.ValidateMigration, 152 NewFacade: migrationminion.NewFacade, 153 NewWorker: migrationminion.NewWorker, 154 }), 155 156 // The logging config updater is a leaf worker that indirectly 157 // controls the messages sent via the log sender according to 158 // changes in environment config. We should only need one of 159 // these in a consolidated agent. 160 loggingConfigUpdaterName: ifNotMigrating(logger.Manifold(logger.ManifoldConfig{ 161 AgentName: agentName, 162 APICallerName: apiCallerName, 163 UpdateAgentFunc: config.UpdateLoggerConfig, 164 })), 165 166 // The api address updater is a leaf worker that rewrites agent config 167 // as the controller addresses change. We should only need one of 168 // these in a consolidated agent. 169 apiAddressUpdaterName: ifNotMigrating(apiaddressupdater.Manifold(apiaddressupdater.ManifoldConfig{ 170 AgentName: agentName, 171 APICallerName: apiCallerName, 172 })), 173 174 // The charmdir resource coordinates whether the charm directory is 175 // available or not; after 'start' hook and before 'stop' hook 176 // executes, and not during upgrades. 177 charmDirName: ifNotMigrating(fortress.Manifold()), 178 179 // HookRetryStrategy uses a retrystrategy worker to get a 180 // retry strategy that will be used by the uniter to run its hooks. 181 hookRetryStrategyName: ifNotMigrating(retrystrategy.Manifold(retrystrategy.ManifoldConfig{ 182 AgentName: agentName, 183 APICallerName: apiCallerName, 184 NewFacade: retrystrategy.NewFacade, 185 NewWorker: retrystrategy.NewRetryStrategyWorker, 186 })), 187 188 // The operator installs and deploys charm containers; 189 // manages the unit's presence in its relations; 190 // creates suboordinate units; runs all the hooks; 191 // sends metrics; etc etc etc. 192 193 operatorName: ifNotMigrating(caasoperator.Manifold(caasoperator.ManifoldConfig{ 194 AgentName: agentName, 195 APICallerName: apiCallerName, 196 ClockName: clockName, 197 MachineLock: config.MachineLock, 198 LeadershipGuarantee: config.LeadershipGuarantee, 199 CharmDirName: charmDirName, 200 HookRetryStrategyName: hookRetryStrategyName, 201 TranslateResolverErr: uniter.TranslateFortressErrors, 202 203 NewWorker: caasoperator.NewWorker, 204 NewClient: func(caller base.APICaller) caasoperator.Client { 205 return caasoperatorapi.NewClient(caller) 206 }, 207 NewCharmDownloader: func(caller base.APICaller) caasoperator.Downloader { 208 return api.NewCharmDownloader(caller) 209 }, 210 })), 211 } 212 } 213 214 func clockManifold(clock clock.Clock) dependency.Manifold { 215 return dependency.Manifold{ 216 Start: func(dependency.Context) (worker.Worker, error) { 217 return engine.NewValueWorker(clock) 218 }, 219 Output: engine.ValueWorkerOutput, 220 } 221 } 222 223 var ifFullyUpgraded = engine.Housing{ 224 Flags: []string{ 225 upgradeStepsFlagName, 226 }, 227 }.Decorate 228 229 var ifNotMigrating = engine.Housing{ 230 Flags: []string{ 231 migrationInactiveFlagName, 232 }, 233 Occupy: migrationFortressName, 234 }.Decorate 235 236 const ( 237 agentName = "agent" 238 apiConfigWatcherName = "api-config-watcher" 239 apiCallerName = "api-caller" 240 clockName = "clock" 241 operatorName = "operator" 242 logSenderName = "log-sender" 243 244 charmDirName = "charm-dir" 245 hookRetryStrategyName = "hook-retry-strategy" 246 247 upgradeStepsGateName = "upgrade-steps-gate" 248 upgradeStepsFlagName = "upgrade-steps-flag" 249 250 migrationFortressName = "migration-fortress" 251 migrationInactiveFlagName = "migration-inactive-flag" 252 migrationMinionName = "migration-minion" 253 254 loggingConfigUpdaterName = "logging-config-updater" 255 apiAddressUpdaterName = "api-address-updater" 256 )