github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/apiserver/worker.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 "context" 8 "fmt" 9 "net/http" 10 11 "github.com/juju/clock" 12 "github.com/juju/errors" 13 "github.com/juju/pubsub/v2" 14 "github.com/juju/worker/v3" 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/authentication/jwt" 20 "github.com/juju/juju/apiserver/authentication/macaroon" 21 jujucontroller "github.com/juju/juju/controller" 22 "github.com/juju/juju/core/auditlog" 23 "github.com/juju/juju/core/cache" 24 coredatabase "github.com/juju/juju/core/database" 25 "github.com/juju/juju/core/lease" 26 "github.com/juju/juju/core/multiwatcher" 27 "github.com/juju/juju/core/presence" 28 "github.com/juju/juju/state" 29 "github.com/juju/juju/worker/syslogger" 30 ) 31 32 // Config is the configuration required for running an API server worker. 33 type Config struct { 34 AgentConfig agent.Config 35 Clock clock.Clock 36 Hub *pubsub.StructuredHub 37 Presence presence.Recorder 38 Mux *apiserverhttp.Mux 39 MultiwatcherFactory multiwatcher.Factory 40 LocalMacaroonAuthenticator macaroon.LocalMacaroonAuthenticator 41 StatePool *state.StatePool 42 Controller *cache.Controller 43 LeaseManager lease.Manager 44 SysLogger syslogger.SysLogger 45 RegisterIntrospectionHTTPHandlers func(func(path string, _ http.Handler)) 46 UpgradeComplete func() bool 47 GetAuditConfig func() auditlog.Config 48 NewServer NewServerFunc 49 MetricsCollector *apiserver.Collector 50 EmbeddedCommand apiserver.ExecEmbeddedCommandFunc 51 CharmhubHTTPClient HTTPClient 52 // DBGetter supplies sql.DB references on request, for named databases. 53 DBGetter coredatabase.DBGetter 54 } 55 56 type HTTPClient interface { 57 Do(*http.Request) (*http.Response, error) 58 } 59 60 // NewServerFunc is the type of function that will be used 61 // by the worker to create a new API server. 62 type NewServerFunc func(apiserver.ServerConfig) (worker.Worker, error) 63 64 // Validate validates the API server configuration. 65 func (config Config) Validate() error { 66 if config.AgentConfig == nil { 67 return errors.NotValidf("nil AgentConfig") 68 } 69 if config.Clock == nil { 70 return errors.NotValidf("nil Clock") 71 } 72 if config.Hub == nil { 73 return errors.NotValidf("nil Hub") 74 } 75 if config.Presence == nil { 76 return errors.NotValidf("nil Presence") 77 } 78 if config.StatePool == nil { 79 return errors.NotValidf("nil StatePool") 80 } 81 if config.Controller == nil { 82 return errors.NotValidf("nil Controller") 83 } 84 if config.Mux == nil { 85 return errors.NotValidf("nil Mux") 86 } 87 if config.MultiwatcherFactory == nil { 88 return errors.NotValidf("nil MultiwatcherFactory") 89 } 90 if config.LocalMacaroonAuthenticator == nil { 91 return errors.NotValidf("nil LocalMacaroonAuthenticator") 92 } 93 if config.LeaseManager == nil { 94 return errors.NotValidf("nil LeaseManager") 95 } 96 if config.RegisterIntrospectionHTTPHandlers == nil { 97 return errors.NotValidf("nil RegisterIntrospectionHTTPHandlers") 98 } 99 if config.SysLogger == nil { 100 return errors.NotValidf("nil SysLogger") 101 } 102 if config.UpgradeComplete == nil { 103 return errors.NotValidf("nil UpgradeComplete") 104 } 105 if config.NewServer == nil { 106 return errors.NotValidf("nil NewServer") 107 } 108 if config.MetricsCollector == nil { 109 return errors.NotValidf("nil MetricsCollector") 110 } 111 if config.CharmhubHTTPClient == nil { 112 return errors.NotValidf("nil CharmhubHTTPClient") 113 } 114 if config.DBGetter == nil { 115 return errors.NotValidf("nil DBGetter") 116 } 117 return nil 118 } 119 120 // NewWorker returns a new API server worker, with the given configuration. 121 func NewWorker(config Config) (worker.Worker, error) { 122 if err := config.Validate(); err != nil { 123 return nil, errors.Trace(err) 124 } 125 126 logSinkConfig, err := getLogSinkConfig(config.AgentConfig) 127 if err != nil { 128 return nil, errors.Annotate(err, "getting log sink config") 129 } 130 131 systemState, err := config.StatePool.SystemState() 132 if err != nil { 133 return nil, errors.Trace(err) 134 } 135 controllerConfig, err := systemState.ControllerConfig() 136 if err != nil { 137 return nil, errors.Annotate(err, "cannot fetch the controller config") 138 } 139 140 observerFactory, err := newObserverFn( 141 config.AgentConfig, 142 controllerConfig, 143 config.Clock, 144 config.Hub, 145 config.MetricsCollector, 146 ) 147 if err != nil { 148 return nil, errors.Annotate(err, "cannot create RPC observer factory") 149 } 150 151 jwtAuthenticator, err := gatherJWTAuthenticator(controllerConfig) 152 if err != nil { 153 return nil, fmt.Errorf("gathering authenticators for apiserver: %w", err) 154 } 155 156 serverConfig := apiserver.ServerConfig{ 157 StatePool: config.StatePool, 158 Controller: config.Controller, 159 Clock: config.Clock, 160 Tag: config.AgentConfig.Tag(), 161 DataDir: config.AgentConfig.DataDir(), 162 LogDir: config.AgentConfig.LogDir(), 163 Hub: config.Hub, 164 Presence: config.Presence, 165 MultiwatcherFactory: config.MultiwatcherFactory, 166 Mux: config.Mux, 167 LocalMacaroonAuthenticator: config.LocalMacaroonAuthenticator, 168 JWTAuthenticator: jwtAuthenticator, 169 UpgradeComplete: config.UpgradeComplete, 170 PublicDNSName: controllerConfig.AutocertDNSName(), 171 AllowModelAccess: controllerConfig.AllowModelAccess(), 172 NewObserver: observerFactory, 173 RegisterIntrospectionHandlers: config.RegisterIntrospectionHTTPHandlers, 174 MetricsCollector: config.MetricsCollector, 175 LogSinkConfig: &logSinkConfig, 176 GetAuditConfig: config.GetAuditConfig, 177 LeaseManager: config.LeaseManager, 178 ExecEmbeddedCommand: config.EmbeddedCommand, 179 SysLogger: config.SysLogger, 180 CharmhubHTTPClient: config.CharmhubHTTPClient, 181 DBGetter: config.DBGetter, 182 } 183 return config.NewServer(serverConfig) 184 } 185 186 // gatherJWTAuthenticator is responsible for building up the jwt authenticator 187 // if this controller has been provisioned to trust external jwt tokens. 188 func gatherJWTAuthenticator(controllerConfig jujucontroller.Config) (jwt.Authenticator, error) { 189 jwtRefreshURL := controllerConfig.LoginTokenRefreshURL() 190 if jwtRefreshURL == "" { 191 return nil, nil 192 } 193 jwtAuthenticator := jwt.NewAuthenticator(jwtRefreshURL) 194 if err := jwtAuthenticator.RegisterJWKSCache(context.Background()); err != nil { 195 return nil, err 196 } 197 return jwtAuthenticator, nil 198 } 199 200 func newServerShim(config apiserver.ServerConfig) (worker.Worker, error) { 201 return apiserver.NewServer(config) 202 } 203 204 // NewMetricsCollector returns a new apiserver collector 205 func NewMetricsCollector() *apiserver.Collector { 206 return apiserver.NewMetricsCollector() 207 }