github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/apiserver/manifold.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apiserver 5 6 import ( 7 "net/http" 8 9 "github.com/juju/clock" 10 "github.com/juju/errors" 11 "github.com/juju/pubsub" 12 "github.com/prometheus/client_golang/prometheus" 13 "gopkg.in/juju/worker.v1" 14 "gopkg.in/juju/worker.v1/dependency" 15 16 "github.com/juju/juju/agent" 17 "github.com/juju/juju/apiserver" 18 "github.com/juju/juju/apiserver/apiserverhttp" 19 "github.com/juju/juju/apiserver/httpcontext" 20 "github.com/juju/juju/core/auditlog" 21 "github.com/juju/juju/core/cache" 22 "github.com/juju/juju/core/lease" 23 "github.com/juju/juju/core/presence" 24 "github.com/juju/juju/state" 25 "github.com/juju/juju/worker/common" 26 "github.com/juju/juju/worker/gate" 27 workerstate "github.com/juju/juju/worker/state" 28 ) 29 30 // ManifoldConfig holds the information necessary to run an apiserver 31 // worker in a dependency.Engine. 32 type ManifoldConfig struct { 33 AgentName string 34 AuthenticatorName string 35 ClockName string 36 ModelCacheName string 37 MuxName string 38 RestoreStatusName string 39 StateName string 40 UpgradeGateName string 41 AuditConfigUpdaterName string 42 LeaseManagerName string 43 RaftTransportName string 44 45 PrometheusRegisterer prometheus.Registerer 46 RegisterIntrospectionHTTPHandlers func(func(path string, _ http.Handler)) 47 Hub *pubsub.StructuredHub 48 Presence presence.Recorder 49 50 NewWorker func(Config) (worker.Worker, error) 51 NewMetricsCollector func() *apiserver.Collector 52 } 53 54 // Validate validates the manifold configuration. 55 func (config ManifoldConfig) Validate() error { 56 if config.AgentName == "" { 57 return errors.NotValidf("empty AgentName") 58 } 59 if config.AuthenticatorName == "" { 60 return errors.NotValidf("empty AuthenticatorName") 61 } 62 if config.ClockName == "" { 63 return errors.NotValidf("empty ClockName") 64 } 65 if config.ModelCacheName == "" { 66 return errors.NotValidf("empty ModelCacheName") 67 } 68 if config.MuxName == "" { 69 return errors.NotValidf("empty MuxName") 70 } 71 if config.RestoreStatusName == "" { 72 return errors.NotValidf("empty RestoreStatusName") 73 } 74 if config.StateName == "" { 75 return errors.NotValidf("empty StateName") 76 } 77 if config.UpgradeGateName == "" { 78 return errors.NotValidf("empty UpgradeGateName") 79 } 80 if config.AuditConfigUpdaterName == "" { 81 return errors.NotValidf("empty AuditConfigUpdaterName") 82 } 83 if config.LeaseManagerName == "" { 84 return errors.NotValidf("empty LeaseManagerName") 85 } 86 if config.RaftTransportName == "" { 87 return errors.NotValidf("empty RaftTransportName") 88 } 89 if config.PrometheusRegisterer == nil { 90 return errors.NotValidf("nil PrometheusRegisterer") 91 } 92 if config.RegisterIntrospectionHTTPHandlers == nil { 93 return errors.NotValidf("nil RegisterIntrospectionHTTPHandlers") 94 } 95 if config.Hub == nil { 96 return errors.NotValidf("nil Hub") 97 } 98 if config.Presence == nil { 99 return errors.NotValidf("nil Presence") 100 } 101 if config.NewWorker == nil { 102 return errors.NotValidf("nil NewWorker") 103 } 104 if config.NewMetricsCollector == nil { 105 return errors.NotValidf("nil NewMetricsCollector") 106 } 107 return nil 108 } 109 110 // Manifold returns a dependency.Manifold that will run an apiserver 111 // worker. The manifold outputs an *apiserverhttp.Mux, for other workers 112 // to register handlers against. 113 func Manifold(config ManifoldConfig) dependency.Manifold { 114 return dependency.Manifold{ 115 Inputs: []string{ 116 config.AgentName, 117 config.AuthenticatorName, 118 config.ClockName, 119 config.ModelCacheName, 120 config.MuxName, 121 config.RestoreStatusName, 122 config.StateName, 123 config.UpgradeGateName, 124 config.AuditConfigUpdaterName, 125 config.LeaseManagerName, 126 config.RaftTransportName, 127 }, 128 Start: config.start, 129 } 130 } 131 132 // start is a method on ManifoldConfig because it's more readable than a closure. 133 func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) { 134 if err := config.Validate(); err != nil { 135 return nil, errors.Trace(err) 136 } 137 138 var agent agent.Agent 139 if err := context.Get(config.AgentName, &agent); err != nil { 140 return nil, errors.Trace(err) 141 } 142 143 var clock clock.Clock 144 if err := context.Get(config.ClockName, &clock); err != nil { 145 return nil, errors.Trace(err) 146 } 147 148 var mux *apiserverhttp.Mux 149 if err := context.Get(config.MuxName, &mux); err != nil { 150 return nil, errors.Trace(err) 151 } 152 153 var authenticator httpcontext.LocalMacaroonAuthenticator 154 if err := context.Get(config.AuthenticatorName, &authenticator); err != nil { 155 return nil, errors.Trace(err) 156 } 157 158 var restoreStatus func() state.RestoreStatus 159 if err := context.Get(config.RestoreStatusName, &restoreStatus); err != nil { 160 return nil, errors.Trace(err) 161 } 162 163 var stTracker workerstate.StateTracker 164 if err := context.Get(config.StateName, &stTracker); err != nil { 165 return nil, errors.Trace(err) 166 } 167 168 var controller *cache.Controller 169 if err := context.Get(config.ModelCacheName, &controller); err != nil { 170 return nil, errors.Trace(err) 171 } 172 173 var upgradeLock gate.Waiter 174 if err := context.Get(config.UpgradeGateName, &upgradeLock); err != nil { 175 return nil, errors.Trace(err) 176 } 177 178 var getAuditConfig func() auditlog.Config 179 if err := context.Get(config.AuditConfigUpdaterName, &getAuditConfig); err != nil { 180 return nil, errors.Trace(err) 181 } 182 183 var leaseManager lease.Manager 184 if err := context.Get(config.LeaseManagerName, &leaseManager); err != nil { 185 return nil, errors.Trace(err) 186 } 187 188 // We don't need anything from the raft-transport but we need to 189 // tie the lifetime of this worker to it - otherwise http-server 190 // will hang waiting for this to release the mux. 191 if err := context.Get(config.RaftTransportName, nil); err != nil { 192 return nil, errors.Trace(err) 193 } 194 195 // Get the state pool after grabbing dependencies so we don't need 196 // to remember to call Done on it if they're not running yet. 197 statePool, err := stTracker.Use() 198 if err != nil { 199 return nil, errors.Trace(err) 200 } 201 202 // Register the metrics collector against the prometheus register. 203 metricsCollector := config.NewMetricsCollector() 204 if err := config.PrometheusRegisterer.Register(metricsCollector); err != nil { 205 return nil, errors.Trace(err) 206 } 207 208 w, err := config.NewWorker(Config{ 209 AgentConfig: agent.CurrentConfig(), 210 Clock: clock, 211 Mux: mux, 212 StatePool: statePool, 213 Controller: controller, 214 LeaseManager: leaseManager, 215 RegisterIntrospectionHTTPHandlers: config.RegisterIntrospectionHTTPHandlers, 216 RestoreStatus: restoreStatus, 217 UpgradeComplete: upgradeLock.IsUnlocked, 218 Hub: config.Hub, 219 Presence: config.Presence, 220 Authenticator: authenticator, 221 GetAuditConfig: getAuditConfig, 222 NewServer: newServerShim, 223 MetricsCollector: metricsCollector, 224 }) 225 if err != nil { 226 stTracker.Done() 227 return nil, errors.Trace(err) 228 } 229 mux.AddClient() 230 return common.NewCleanupWorker(w, func() { 231 mux.ClientDone() 232 stTracker.Done() 233 234 // clean up the metrics for the worker, so the next time a worker is 235 // created we can safely register the metrics again. 236 config.PrometheusRegisterer.Unregister(metricsCollector) 237 }), nil 238 }