1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
12
"launchpad.net/juju-core/names"
13
"launchpad.net/juju-core/rpc"
14
"launchpad.net/juju-core/state"
15
"launchpad.net/juju-core/state/apiserver/agent"
16
"launchpad.net/juju-core/state/apiserver/charmrevisionupdater"
17
"launchpad.net/juju-core/state/apiserver/client"
18
"launchpad.net/juju-core/state/apiserver/common"
19
"launchpad.net/juju-core/state/apiserver/deployer"
20
"launchpad.net/juju-core/state/apiserver/environment"
21
"launchpad.net/juju-core/state/apiserver/firewaller"
22
"launchpad.net/juju-core/state/apiserver/keymanager"
23
"launchpad.net/juju-core/state/apiserver/keyupdater"
24
loggerapi "launchpad.net/juju-core/state/apiserver/logger"
25
"launchpad.net/juju-core/state/apiserver/machine"
26
"launchpad.net/juju-core/state/apiserver/provisioner"
27
"launchpad.net/juju-core/state/apiserver/rsyslog"
28
"launchpad.net/juju-core/state/apiserver/uniter"
29
"launchpad.net/juju-core/state/apiserver/upgrader"
30
"launchpad.net/juju-core/state/apiserver/usermanager"
31
"launchpad.net/juju-core/state/multiwatcher"
34
type clientAPI struct{ *client.API }
36
type taggedAuthenticator interface {
41
// maxPingInterval defines the timeframe until the ping
42
// timeout closes the monitored connection.
43
// TODO(mue): Idea by Roger: Move to API (e.g. params) so
44
// that the pinging there may depend on the interval.
45
var maxPingInterval = 3 * time.Minute
47
// srvRoot represents a single client's connection to the state
48
// after it has logged in.
53
resources *common.Resources
54
pingTimeout *pingTimeout
56
entity taggedAuthenticator
59
// newSrvRoot creates the client's connection representation
60
// and starts a ping timeout for the monitoring of this
62
func newSrvRoot(root *initialRoot, entity taggedAuthenticator) *srvRoot {
65
rpcConn: root.rpcConn,
66
resources: common.NewResources(),
69
r.clientAPI.API = client.NewAPI(r.srv.state, r.resources, r, r.srv.dataDir)
73
// Kill implements rpc.Killer. It cleans up any resources that need
74
// cleaning up to ensure that all outstanding requests return.
75
func (r *srvRoot) Kill() {
77
if r.pingTimeout != nil {
82
// requireAgent checks whether the current client is an agent and hence
83
// may access the agent APIs. We filter out non-agents when calling one
84
// of the accessor functions (Machine, Unit, etc) which avoids us making
85
// the check in every single request method.
86
func (r *srvRoot) requireAgent() error {
87
if !isAgent(r.entity) {
93
// requireClient returns an error unless the current
94
// client is a juju client user.
95
func (r *srvRoot) requireClient() error {
96
if isAgent(r.entity) {
102
// KeyManager returns an object that provides access to the KeyManager API
103
// facade. The id argument is reserved for future use and currently
104
// needs to be empty.
105
func (r *srvRoot) KeyManager(id string) (*keymanager.KeyManagerAPI, error) {
107
return nil, common.ErrBadId
109
return keymanager.NewKeyManagerAPI(r.srv.state, r.resources, r)
112
// UserManager returns an object that provides access to the UserManager API
113
// facade. The id argument is reserved for future use and currently
115
func (r *srvRoot) UserManager(id string) (*usermanager.UserManagerAPI, error) {
117
return nil, common.ErrBadId
119
return usermanager.NewUserManagerAPI(r.srv.state, r)
122
// Machiner returns an object that provides access to the Machiner API
123
// facade. The id argument is reserved for future use and currently
124
// needs to be empty.
125
func (r *srvRoot) Machiner(id string) (*machine.MachinerAPI, error) {
127
// Safeguard id for possible future use.
128
return nil, common.ErrBadId
130
return machine.NewMachinerAPI(r.srv.state, r.resources, r)
133
// Provisioner returns an object that provides access to the
134
// Provisioner API facade. The id argument is reserved for future use
135
// and currently needs to be empty.
136
func (r *srvRoot) Provisioner(id string) (*provisioner.ProvisionerAPI, error) {
138
// Safeguard id for possible future use.
139
return nil, common.ErrBadId
141
return provisioner.NewProvisionerAPI(r.srv.state, r.resources, r)
144
// Uniter returns an object that provides access to the Uniter API
145
// facade. The id argument is reserved for future use and currently
146
// needs to be empty.
147
func (r *srvRoot) Uniter(id string) (*uniter.UniterAPI, error) {
149
// Safeguard id for possible future use.
150
return nil, common.ErrBadId
152
return uniter.NewUniterAPI(r.srv.state, r.resources, r)
155
// Firewaller returns an object that provides access to the Firewaller
156
// API facade. The id argument is reserved for future use and
157
// currently needs to be empty.
158
func (r *srvRoot) Firewaller(id string) (*firewaller.FirewallerAPI, error) {
160
// Safeguard id for possible future use.
161
return nil, common.ErrBadId
163
return firewaller.NewFirewallerAPI(r.srv.state, r.resources, r)
166
// Agent returns an object that provides access to the
167
// agent API. The id argument is reserved for future use and must currently
169
func (r *srvRoot) Agent(id string) (*agent.API, error) {
171
return nil, common.ErrBadId
173
return agent.NewAPI(r.srv.state, r)
176
// Deployer returns an object that provides access to the Deployer API facade.
177
// The id argument is reserved for future use and must be empty.
178
func (r *srvRoot) Deployer(id string) (*deployer.DeployerAPI, error) {
180
// TODO(dimitern): There is no direct test for this
181
return nil, common.ErrBadId
183
return deployer.NewDeployerAPI(r.srv.state, r.resources, r)
186
// Environment returns an object that provides access to the Environment API
187
// facade. The id argument is reserved for future use and currently needs to
189
func (r *srvRoot) Environment(id string) (*environment.EnvironmentAPI, error) {
191
// Safeguard id for possible future use.
192
return nil, common.ErrBadId
194
return environment.NewEnvironmentAPI(r.srv.state, r.resources, r)
197
// Rsyslog returns an object that provides access to the Rsyslog API
198
// facade. The id argument is reserved for future use and currently needs to
200
func (r *srvRoot) Rsyslog(id string) (*rsyslog.RsyslogAPI, error) {
202
// Safeguard id for possible future use.
203
return nil, common.ErrBadId
205
return rsyslog.NewRsyslogAPI(r.srv.state, r.resources, r)
208
// Logger returns an object that provides access to the Logger API facade.
209
// The id argument is reserved for future use and must be empty.
210
func (r *srvRoot) Logger(id string) (*loggerapi.LoggerAPI, error) {
212
// TODO: There is no direct test for this
213
return nil, common.ErrBadId
215
return loggerapi.NewLoggerAPI(r.srv.state, r.resources, r)
218
// Upgrader returns an object that provides access to the Upgrader API facade.
219
// The id argument is reserved for future use and must be empty.
220
func (r *srvRoot) Upgrader(id string) (upgrader.Upgrader, error) {
222
// TODO: There is no direct test for this
223
return nil, common.ErrBadId
225
// The type of upgrader we return depends on who is asking.
226
// Machines get an UpgraderAPI, units get a UnitUpgraderAPI.
227
// This is tested in the state/api/upgrader package since there
228
// are currently no direct srvRoot tests.
229
tagKind, _, err := names.ParseTag(r.GetAuthTag(), "")
231
return nil, common.ErrPerm
234
case names.MachineTagKind:
235
return upgrader.NewUpgraderAPI(r.srv.state, r.resources, r)
236
case names.UnitTagKind:
237
return upgrader.NewUnitUpgraderAPI(r.srv.state, r.resources, r, r.srv.dataDir)
239
// Not a machine or unit.
240
return nil, common.ErrPerm
243
// KeyUpdater returns an object that provides access to the KeyUpdater API facade.
244
// The id argument is reserved for future use and must be empty.
245
func (r *srvRoot) KeyUpdater(id string) (*keyupdater.KeyUpdaterAPI, error) {
247
// TODO: There is no direct test for this
248
return nil, common.ErrBadId
250
return keyupdater.NewKeyUpdaterAPI(r.srv.state, r.resources, r)
253
// CharmRevisionUpdater returns an object that provides access to the CharmRevisionUpdater API facade.
254
// The id argument is reserved for future use and must be empty.
255
func (r *srvRoot) CharmRevisionUpdater(id string) (*charmrevisionupdater.CharmRevisionUpdaterAPI, error) {
257
// TODO: There is no direct test for this
258
return nil, common.ErrBadId
260
return charmrevisionupdater.NewCharmRevisionUpdaterAPI(r.srv.state, r.resources, r)
263
// NotifyWatcher returns an object that provides
264
// API access to methods on a state.NotifyWatcher.
265
// Each client has its own current set of watchers, stored
267
func (r *srvRoot) NotifyWatcher(id string) (*srvNotifyWatcher, error) {
268
if err := r.requireAgent(); err != nil {
271
watcher, ok := r.resources.Get(id).(state.NotifyWatcher)
273
return nil, common.ErrUnknownWatcher
275
return &srvNotifyWatcher{
278
resources: r.resources,
282
// StringsWatcher returns an object that provides API access to
283
// methods on a state.StringsWatcher. Each client has its own
284
// current set of watchers, stored in r.resources.
285
func (r *srvRoot) StringsWatcher(id string) (*srvStringsWatcher, error) {
286
if err := r.requireAgent(); err != nil {
289
watcher, ok := r.resources.Get(id).(state.StringsWatcher)
291
return nil, common.ErrUnknownWatcher
293
return &srvStringsWatcher{
296
resources: r.resources,
300
// RelationUnitsWatcher returns an object that provides API access to
301
// methods on a state.RelationUnitsWatcher. Each client has its own
302
// current set of watchers, stored in r.resources.
303
func (r *srvRoot) RelationUnitsWatcher(id string) (*srvRelationUnitsWatcher, error) {
304
if err := r.requireAgent(); err != nil {
307
watcher, ok := r.resources.Get(id).(state.RelationUnitsWatcher)
309
return nil, common.ErrUnknownWatcher
311
return &srvRelationUnitsWatcher{
314
resources: r.resources,
318
// AllWatcher returns an object that provides API access to methods on
319
// a state/multiwatcher.Watcher, which watches any changes to the
320
// state. Each client has its own current set of watchers, stored in
322
func (r *srvRoot) AllWatcher(id string) (*srvClientAllWatcher, error) {
323
if err := r.requireClient(); err != nil {
326
watcher, ok := r.resources.Get(id).(*multiwatcher.Watcher)
328
return nil, common.ErrUnknownWatcher
330
return &srvClientAllWatcher{
333
resources: r.resources,
337
// Pinger returns an object that can be pinged
338
// by calling its Ping method. If this method
339
// is not called frequently enough, the connection
341
func (r *srvRoot) Pinger(id string) (pinger, error) {
342
if r.pingTimeout == nil {
343
return nullPinger{}, nil
345
return r.pingTimeout, nil
348
type nullPinger struct{}
350
func (nullPinger) Ping() {}
352
// AuthMachineAgent returns whether the current client is a machine agent.
353
func (r *srvRoot) AuthMachineAgent() bool {
354
_, ok := r.entity.(*state.Machine)
358
// AuthUnitAgent returns whether the current client is a unit agent.
359
func (r *srvRoot) AuthUnitAgent() bool {
360
_, ok := r.entity.(*state.Unit)
364
// AuthOwner returns whether the authenticated user's tag matches the
366
func (r *srvRoot) AuthOwner(tag string) bool {
367
return r.entity.Tag() == tag
370
// AuthEnvironManager returns whether the authenticated user is a
371
// machine with running the ManageEnviron job.
372
func (r *srvRoot) AuthEnvironManager() bool {
373
return isMachineWithJob(r.entity, state.JobManageEnviron)
376
// AuthClient returns whether the authenticated entity is a client
378
func (r *srvRoot) AuthClient() bool {
379
return !isAgent(r.entity)
382
// GetAuthTag returns the tag of the authenticated entity.
383
func (r *srvRoot) GetAuthTag() string {
384
return r.entity.Tag()
387
// GetAuthEntity returns the authenticated entity.
388
func (r *srvRoot) GetAuthEntity() state.Entity {
392
// pinger describes a type that can be pinged.
393
type pinger interface {
397
// pingTimeout listens for pings and will call the
398
// passed action in case of a timeout. This way broken
399
// or inactive connections can be closed.
400
type pingTimeout struct {
403
timeout time.Duration
407
// newPingTimeout returns a new pingTimeout instance
408
// that invokes the given action asynchronously if there
409
// is more than the given timeout interval between calls
410
// to its Ping method.
411
func newPingTimeout(action func(), timeout time.Duration) *pingTimeout {
415
reset: make(chan struct{}),
419
pt.tomb.Kill(pt.loop())
424
// Ping is used by the client heartbeat monitor and resets
426
func (pt *pingTimeout) Ping() {
428
case <-pt.tomb.Dying():
429
case pt.reset <- struct{}{}:
433
// stop terminates the ping timeout.
434
func (pt *pingTimeout) stop() error {
436
return pt.tomb.Wait()
439
// loop waits for a reset signal, otherwise it performs
440
// the initially passed action.
441
func (pt *pingTimeout) loop() error {
442
timer := time.NewTimer(pt.timeout)
446
case <-pt.tomb.Dying():
450
return errors.New("ping timeout")
452
timer.Reset(pt.timeout)