github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/apiserver/root.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apiserver 5 6 import ( 7 "errors" 8 "time" 9 10 "github.com/juju/names" 11 "launchpad.net/tomb" 12 13 "github.com/juju/juju/rpc" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/state/apiserver/agent" 16 "github.com/juju/juju/state/apiserver/charmrevisionupdater" 17 "github.com/juju/juju/state/apiserver/client" 18 "github.com/juju/juju/state/apiserver/common" 19 "github.com/juju/juju/state/apiserver/deployer" 20 "github.com/juju/juju/state/apiserver/environment" 21 "github.com/juju/juju/state/apiserver/firewaller" 22 "github.com/juju/juju/state/apiserver/keymanager" 23 "github.com/juju/juju/state/apiserver/keyupdater" 24 loggerapi "github.com/juju/juju/state/apiserver/logger" 25 "github.com/juju/juju/state/apiserver/machine" 26 "github.com/juju/juju/state/apiserver/networker" 27 "github.com/juju/juju/state/apiserver/provisioner" 28 "github.com/juju/juju/state/apiserver/rsyslog" 29 "github.com/juju/juju/state/apiserver/uniter" 30 "github.com/juju/juju/state/apiserver/upgrader" 31 "github.com/juju/juju/state/apiserver/usermanager" 32 "github.com/juju/juju/state/multiwatcher" 33 ) 34 35 type clientAPI struct{ *client.API } 36 37 type taggedAuthenticator interface { 38 state.Entity 39 state.Authenticator 40 } 41 42 var ( 43 // maxClientPingInterval defines the timeframe until the ping timeout 44 // closes the monitored connection. TODO(mue): Idea by Roger: 45 // Move to API (e.g. params) so that the pinging there may 46 // depend on the interval. 47 maxClientPingInterval = 3 * time.Minute 48 49 // mongoPingInterval defines the interval at which an API server 50 // will ping the mongo session to make sure that it's still 51 // alive. When the ping returns an error, the server will be 52 // terminated. 53 mongoPingInterval = 10 * time.Second 54 ) 55 56 // srvRoot represents a single client's connection to the state 57 // after it has logged in. 58 type srvRoot struct { 59 clientAPI 60 srv *Server 61 rpcConn *rpc.Conn 62 resources *common.Resources 63 64 entity taggedAuthenticator 65 } 66 67 // newSrvRoot creates the client's connection representation 68 // and starts a ping timeout for the monitoring of this 69 // connection. 70 func newSrvRoot(root *initialRoot, entity taggedAuthenticator) *srvRoot { 71 r := &srvRoot{ 72 srv: root.srv, 73 rpcConn: root.rpcConn, 74 resources: common.NewResources(), 75 entity: entity, 76 } 77 r.resources.RegisterNamed("dataDir", common.StringResource(r.srv.dataDir)) 78 r.clientAPI.API = client.NewAPI(r.srv.state, r.resources, r) 79 return r 80 } 81 82 // Kill implements rpc.Killer. It cleans up any resources that need 83 // cleaning up to ensure that all outstanding requests return. 84 func (r *srvRoot) Kill() { 85 r.resources.StopAll() 86 } 87 88 // requireAgent checks whether the current client is an agent and hence 89 // may access the agent APIs. We filter out non-agents when calling one 90 // of the accessor functions (Machine, Unit, etc) which avoids us making 91 // the check in every single request method. 92 func (r *srvRoot) requireAgent() error { 93 if !isAgent(r.entity) { 94 return common.ErrPerm 95 } 96 return nil 97 } 98 99 // requireClient returns an error unless the current 100 // client is a juju client user. 101 func (r *srvRoot) requireClient() error { 102 if isAgent(r.entity) { 103 return common.ErrPerm 104 } 105 return nil 106 } 107 108 // KeyManager returns an object that provides access to the KeyManager API 109 // facade. The id argument is reserved for future use and currently 110 // needs to be empty. 111 func (r *srvRoot) KeyManager(id string) (*keymanager.KeyManagerAPI, error) { 112 if id != "" { 113 return nil, common.ErrBadId 114 } 115 return keymanager.NewKeyManagerAPI(r.srv.state, r.resources, r) 116 } 117 118 // UserManager returns an object that provides access to the UserManager API 119 // facade. The id argument is reserved for future use and currently 120 // needs to be empty 121 func (r *srvRoot) UserManager(id string) (*usermanager.UserManagerAPI, error) { 122 if id != "" { 123 return nil, common.ErrBadId 124 } 125 return usermanager.NewUserManagerAPI(r.srv.state, r) 126 } 127 128 // Machiner returns an object that provides access to the Machiner API 129 // facade. The id argument is reserved for future use and currently 130 // needs to be empty. 131 func (r *srvRoot) Machiner(id string) (*machine.MachinerAPI, error) { 132 if id != "" { 133 // Safeguard id for possible future use. 134 return nil, common.ErrBadId 135 } 136 return machine.NewMachinerAPI(r.srv.state, r.resources, r) 137 } 138 139 // Networker returns an object that provides access to the 140 // Networker API facade. The id argument is reserved for future use 141 // and currently needs to be empty. 142 func (r *srvRoot) Networker(id string) (*networker.NetworkerAPI, error) { 143 if id != "" { 144 // Safeguard id for possible future use. 145 return nil, common.ErrBadId 146 } 147 return networker.NewNetworkerAPI(r.srv.state, r.resources, r) 148 } 149 150 // Provisioner returns an object that provides access to the 151 // Provisioner API facade. The id argument is reserved for future use 152 // and currently needs to be empty. 153 func (r *srvRoot) Provisioner(id string) (*provisioner.ProvisionerAPI, error) { 154 if id != "" { 155 // Safeguard id for possible future use. 156 return nil, common.ErrBadId 157 } 158 return provisioner.NewProvisionerAPI(r.srv.state, r.resources, r) 159 } 160 161 // Uniter returns an object that provides access to the Uniter API 162 // facade. The id argument is reserved for future use and currently 163 // needs to be empty. 164 func (r *srvRoot) Uniter(id string) (*uniter.UniterAPI, error) { 165 if id != "" { 166 // Safeguard id for possible future use. 167 return nil, common.ErrBadId 168 } 169 return uniter.NewUniterAPI(r.srv.state, r.resources, r) 170 } 171 172 // Firewaller returns an object that provides access to the Firewaller 173 // API facade. The id argument is reserved for future use and 174 // currently needs to be empty. 175 func (r *srvRoot) Firewaller(id string) (*firewaller.FirewallerAPI, error) { 176 if id != "" { 177 // Safeguard id for possible future use. 178 return nil, common.ErrBadId 179 } 180 return firewaller.NewFirewallerAPI(r.srv.state, r.resources, r) 181 } 182 183 // Agent returns an object that provides access to the 184 // agent API. The id argument is reserved for future use and must currently 185 // be empty. 186 func (r *srvRoot) Agent(id string) (*agent.API, error) { 187 if id != "" { 188 return nil, common.ErrBadId 189 } 190 return agent.NewAPI(r.srv.state, r) 191 } 192 193 // Deployer returns an object that provides access to the Deployer API facade. 194 // The id argument is reserved for future use and must be empty. 195 func (r *srvRoot) Deployer(id string) (*deployer.DeployerAPI, error) { 196 if id != "" { 197 // TODO(dimitern): There is no direct test for this 198 return nil, common.ErrBadId 199 } 200 return deployer.NewDeployerAPI(r.srv.state, r.resources, r) 201 } 202 203 // Environment returns an object that provides access to the Environment API 204 // facade. The id argument is reserved for future use and currently needs to 205 // be empty. 206 func (r *srvRoot) Environment(id string) (*environment.EnvironmentAPI, error) { 207 if id != "" { 208 // Safeguard id for possible future use. 209 return nil, common.ErrBadId 210 } 211 return environment.NewEnvironmentAPI(r.srv.state, r.resources, r) 212 } 213 214 // Rsyslog returns an object that provides access to the Rsyslog API 215 // facade. The id argument is reserved for future use and currently needs to 216 // be empty. 217 func (r *srvRoot) Rsyslog(id string) (*rsyslog.RsyslogAPI, error) { 218 if id != "" { 219 // Safeguard id for possible future use. 220 return nil, common.ErrBadId 221 } 222 return rsyslog.NewRsyslogAPI(r.srv.state, r.resources, r) 223 } 224 225 // Logger returns an object that provides access to the Logger API facade. 226 // The id argument is reserved for future use and must be empty. 227 func (r *srvRoot) Logger(id string) (*loggerapi.LoggerAPI, error) { 228 if id != "" { 229 // TODO: There is no direct test for this 230 return nil, common.ErrBadId 231 } 232 return loggerapi.NewLoggerAPI(r.srv.state, r.resources, r) 233 } 234 235 // Upgrader returns an object that provides access to the Upgrader API facade. 236 // The id argument is reserved for future use and must be empty. 237 func (r *srvRoot) Upgrader(id string) (upgrader.Upgrader, error) { 238 if id != "" { 239 // TODO: There is no direct test for this 240 return nil, common.ErrBadId 241 } 242 // The type of upgrader we return depends on who is asking. 243 // Machines get an UpgraderAPI, units get a UnitUpgraderAPI. 244 // This is tested in the state/api/upgrader package since there 245 // are currently no direct srvRoot tests. 246 tagKind, _, err := names.ParseTag(r.GetAuthTag(), "") 247 if err != nil { 248 return nil, common.ErrPerm 249 } 250 switch tagKind { 251 case names.MachineTagKind: 252 return upgrader.NewUpgraderAPI(r.srv.state, r.resources, r) 253 case names.UnitTagKind: 254 return upgrader.NewUnitUpgraderAPI(r.srv.state, r.resources, r) 255 } 256 // Not a machine or unit. 257 return nil, common.ErrPerm 258 } 259 260 // KeyUpdater returns an object that provides access to the KeyUpdater API facade. 261 // The id argument is reserved for future use and must be empty. 262 func (r *srvRoot) KeyUpdater(id string) (*keyupdater.KeyUpdaterAPI, error) { 263 if id != "" { 264 // TODO: There is no direct test for this 265 return nil, common.ErrBadId 266 } 267 return keyupdater.NewKeyUpdaterAPI(r.srv.state, r.resources, r) 268 } 269 270 // CharmRevisionUpdater returns an object that provides access to the CharmRevisionUpdater API facade. 271 // The id argument is reserved for future use and must be empty. 272 func (r *srvRoot) CharmRevisionUpdater(id string) (*charmrevisionupdater.CharmRevisionUpdaterAPI, error) { 273 if id != "" { 274 // TODO: There is no direct test for this 275 return nil, common.ErrBadId 276 } 277 return charmrevisionupdater.NewCharmRevisionUpdaterAPI(r.srv.state, r.resources, r) 278 } 279 280 // NotifyWatcher returns an object that provides 281 // API access to methods on a state.NotifyWatcher. 282 // Each client has its own current set of watchers, stored 283 // in r.resources. 284 func (r *srvRoot) NotifyWatcher(id string) (*srvNotifyWatcher, error) { 285 if err := r.requireAgent(); err != nil { 286 return nil, err 287 } 288 watcher, ok := r.resources.Get(id).(state.NotifyWatcher) 289 if !ok { 290 return nil, common.ErrUnknownWatcher 291 } 292 return &srvNotifyWatcher{ 293 watcher: watcher, 294 id: id, 295 resources: r.resources, 296 }, nil 297 } 298 299 // StringsWatcher returns an object that provides API access to 300 // methods on a state.StringsWatcher. Each client has its own 301 // current set of watchers, stored in r.resources. 302 func (r *srvRoot) StringsWatcher(id string) (*srvStringsWatcher, error) { 303 if err := r.requireAgent(); err != nil { 304 return nil, err 305 } 306 watcher, ok := r.resources.Get(id).(state.StringsWatcher) 307 if !ok { 308 return nil, common.ErrUnknownWatcher 309 } 310 return &srvStringsWatcher{ 311 watcher: watcher, 312 id: id, 313 resources: r.resources, 314 }, nil 315 } 316 317 // RelationUnitsWatcher returns an object that provides API access to 318 // methods on a state.RelationUnitsWatcher. Each client has its own 319 // current set of watchers, stored in r.resources. 320 func (r *srvRoot) RelationUnitsWatcher(id string) (*srvRelationUnitsWatcher, error) { 321 if err := r.requireAgent(); err != nil { 322 return nil, err 323 } 324 watcher, ok := r.resources.Get(id).(state.RelationUnitsWatcher) 325 if !ok { 326 return nil, common.ErrUnknownWatcher 327 } 328 return &srvRelationUnitsWatcher{ 329 watcher: watcher, 330 id: id, 331 resources: r.resources, 332 }, nil 333 } 334 335 // AllWatcher returns an object that provides API access to methods on 336 // a state/multiwatcher.Watcher, which watches any changes to the 337 // state. Each client has its own current set of watchers, stored in 338 // r.resources. 339 func (r *srvRoot) AllWatcher(id string) (*srvClientAllWatcher, error) { 340 if err := r.requireClient(); err != nil { 341 return nil, err 342 } 343 watcher, ok := r.resources.Get(id).(*multiwatcher.Watcher) 344 if !ok { 345 return nil, common.ErrUnknownWatcher 346 } 347 return &srvClientAllWatcher{ 348 watcher: watcher, 349 id: id, 350 resources: r.resources, 351 }, nil 352 } 353 354 // Pinger returns an object that can be pinged 355 // by calling its Ping method. If this method 356 // is not called frequently enough, the connection 357 // will be dropped. 358 func (r *srvRoot) Pinger(id string) (pinger, error) { 359 pingTimeout, ok := r.resources.Get("pingTimeout").(pinger) 360 if !ok { 361 return nullPinger{}, nil 362 } 363 return pingTimeout, nil 364 } 365 366 type nullPinger struct{} 367 368 func (nullPinger) Ping() {} 369 370 // AuthMachineAgent returns whether the current client is a machine agent. 371 func (r *srvRoot) AuthMachineAgent() bool { 372 _, ok := r.entity.(*state.Machine) 373 return ok 374 } 375 376 // AuthUnitAgent returns whether the current client is a unit agent. 377 func (r *srvRoot) AuthUnitAgent() bool { 378 _, ok := r.entity.(*state.Unit) 379 return ok 380 } 381 382 // AuthOwner returns whether the authenticated user's tag matches the 383 // given entity tag. 384 func (r *srvRoot) AuthOwner(tag string) bool { 385 return r.entity.Tag() == tag 386 } 387 388 // AuthEnvironManager returns whether the authenticated user is a 389 // machine with running the ManageEnviron job. 390 func (r *srvRoot) AuthEnvironManager() bool { 391 return isMachineWithJob(r.entity, state.JobManageEnviron) 392 } 393 394 // AuthClient returns whether the authenticated entity is a client 395 // user. 396 func (r *srvRoot) AuthClient() bool { 397 return !isAgent(r.entity) 398 } 399 400 // GetAuthTag returns the tag of the authenticated entity. 401 func (r *srvRoot) GetAuthTag() string { 402 return r.entity.Tag() 403 } 404 405 // GetAuthEntity returns the authenticated entity. 406 func (r *srvRoot) GetAuthEntity() state.Entity { 407 return r.entity 408 } 409 410 // pinger describes a type that can be pinged. 411 type pinger interface { 412 Ping() 413 } 414 415 // pingTimeout listens for pings and will call the 416 // passed action in case of a timeout. This way broken 417 // or inactive connections can be closed. 418 type pingTimeout struct { 419 tomb tomb.Tomb 420 action func() 421 timeout time.Duration 422 reset chan struct{} 423 } 424 425 // newPingTimeout returns a new pingTimeout instance 426 // that invokes the given action asynchronously if there 427 // is more than the given timeout interval between calls 428 // to its Ping method. 429 func newPingTimeout(action func(), timeout time.Duration) *pingTimeout { 430 pt := &pingTimeout{ 431 action: action, 432 timeout: timeout, 433 reset: make(chan struct{}), 434 } 435 go func() { 436 defer pt.tomb.Done() 437 pt.tomb.Kill(pt.loop()) 438 }() 439 return pt 440 } 441 442 // Ping is used by the client heartbeat monitor and resets 443 // the killer. 444 func (pt *pingTimeout) Ping() { 445 select { 446 case <-pt.tomb.Dying(): 447 case pt.reset <- struct{}{}: 448 } 449 } 450 451 // Stop terminates the ping timeout. 452 func (pt *pingTimeout) Stop() error { 453 pt.tomb.Kill(nil) 454 return pt.tomb.Wait() 455 } 456 457 // loop waits for a reset signal, otherwise it performs 458 // the initially passed action. 459 func (pt *pingTimeout) loop() error { 460 timer := time.NewTimer(pt.timeout) 461 defer timer.Stop() 462 for { 463 select { 464 case <-pt.tomb.Dying(): 465 return nil 466 case <-timer.C: 467 go pt.action() 468 return errors.New("ping timeout") 469 case <-pt.reset: 470 timer.Reset(pt.timeout) 471 } 472 } 473 }