~cloud-green/juju-core/charmstore-sdist

« back to all changes in this revision

Viewing changes to launchpad.net/juju-core/state/apiserver/root.go

  • Committer: Casey Marshall
  • Date: 2014-03-27 15:59:46 UTC
  • Revision ID: cmars@cmarstech.com-20140327155946-8huorf37g0zwar43
Source distribution of launchpad.net/juju-core created 20140327105939

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        "launchpad.net/tomb"
 
11
 
 
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"
 
32
)
 
33
 
 
34
type clientAPI struct{ *client.API }
 
35
 
 
36
type taggedAuthenticator interface {
 
37
        state.Entity
 
38
        state.Authenticator
 
39
}
 
40
 
 
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
 
46
 
 
47
// srvRoot represents a single client's connection to the state
 
48
// after it has logged in.
 
49
type srvRoot struct {
 
50
        clientAPI
 
51
        srv         *Server
 
52
        rpcConn     *rpc.Conn
 
53
        resources   *common.Resources
 
54
        pingTimeout *pingTimeout
 
55
 
 
56
        entity taggedAuthenticator
 
57
}
 
58
 
 
59
// newSrvRoot creates the client's connection representation
 
60
// and starts a ping timeout for the monitoring of this
 
61
// connection.
 
62
func newSrvRoot(root *initialRoot, entity taggedAuthenticator) *srvRoot {
 
63
        r := &srvRoot{
 
64
                srv:       root.srv,
 
65
                rpcConn:   root.rpcConn,
 
66
                resources: common.NewResources(),
 
67
                entity:    entity,
 
68
        }
 
69
        r.clientAPI.API = client.NewAPI(r.srv.state, r.resources, r, r.srv.dataDir)
 
70
        return r
 
71
}
 
72
 
 
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() {
 
76
        r.resources.StopAll()
 
77
        if r.pingTimeout != nil {
 
78
                r.pingTimeout.stop()
 
79
        }
 
80
}
 
81
 
 
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) {
 
88
                return common.ErrPerm
 
89
        }
 
90
        return nil
 
91
}
 
92
 
 
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) {
 
97
                return common.ErrPerm
 
98
        }
 
99
        return nil
 
100
}
 
101
 
 
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) {
 
106
        if id != "" {
 
107
                return nil, common.ErrBadId
 
108
        }
 
109
        return keymanager.NewKeyManagerAPI(r.srv.state, r.resources, r)
 
110
}
 
111
 
 
112
// UserManager returns an object that provides access to the UserManager API
 
113
// facade. The id argument is reserved for future use and currently
 
114
// needs to be empty
 
115
func (r *srvRoot) UserManager(id string) (*usermanager.UserManagerAPI, error) {
 
116
        if id != "" {
 
117
                return nil, common.ErrBadId
 
118
        }
 
119
        return usermanager.NewUserManagerAPI(r.srv.state, r)
 
120
}
 
121
 
 
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) {
 
126
        if id != "" {
 
127
                // Safeguard id for possible future use.
 
128
                return nil, common.ErrBadId
 
129
        }
 
130
        return machine.NewMachinerAPI(r.srv.state, r.resources, r)
 
131
}
 
132
 
 
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) {
 
137
        if id != "" {
 
138
                // Safeguard id for possible future use.
 
139
                return nil, common.ErrBadId
 
140
        }
 
141
        return provisioner.NewProvisionerAPI(r.srv.state, r.resources, r)
 
142
}
 
143
 
 
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) {
 
148
        if id != "" {
 
149
                // Safeguard id for possible future use.
 
150
                return nil, common.ErrBadId
 
151
        }
 
152
        return uniter.NewUniterAPI(r.srv.state, r.resources, r)
 
153
}
 
154
 
 
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) {
 
159
        if id != "" {
 
160
                // Safeguard id for possible future use.
 
161
                return nil, common.ErrBadId
 
162
        }
 
163
        return firewaller.NewFirewallerAPI(r.srv.state, r.resources, r)
 
164
}
 
165
 
 
166
// Agent returns an object that provides access to the
 
167
// agent API.  The id argument is reserved for future use and must currently
 
168
// be empty.
 
169
func (r *srvRoot) Agent(id string) (*agent.API, error) {
 
170
        if id != "" {
 
171
                return nil, common.ErrBadId
 
172
        }
 
173
        return agent.NewAPI(r.srv.state, r)
 
174
}
 
175
 
 
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) {
 
179
        if id != "" {
 
180
                // TODO(dimitern): There is no direct test for this
 
181
                return nil, common.ErrBadId
 
182
        }
 
183
        return deployer.NewDeployerAPI(r.srv.state, r.resources, r)
 
184
}
 
185
 
 
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
 
188
// be empty.
 
189
func (r *srvRoot) Environment(id string) (*environment.EnvironmentAPI, error) {
 
190
        if id != "" {
 
191
                // Safeguard id for possible future use.
 
192
                return nil, common.ErrBadId
 
193
        }
 
194
        return environment.NewEnvironmentAPI(r.srv.state, r.resources, r)
 
195
}
 
196
 
 
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
 
199
// be empty.
 
200
func (r *srvRoot) Rsyslog(id string) (*rsyslog.RsyslogAPI, error) {
 
201
        if id != "" {
 
202
                // Safeguard id for possible future use.
 
203
                return nil, common.ErrBadId
 
204
        }
 
205
        return rsyslog.NewRsyslogAPI(r.srv.state, r.resources, r)
 
206
}
 
207
 
 
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) {
 
211
        if id != "" {
 
212
                // TODO: There is no direct test for this
 
213
                return nil, common.ErrBadId
 
214
        }
 
215
        return loggerapi.NewLoggerAPI(r.srv.state, r.resources, r)
 
216
}
 
217
 
 
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) {
 
221
        if id != "" {
 
222
                // TODO: There is no direct test for this
 
223
                return nil, common.ErrBadId
 
224
        }
 
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(), "")
 
230
        if err != nil {
 
231
                return nil, common.ErrPerm
 
232
        }
 
233
        switch tagKind {
 
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)
 
238
        }
 
239
        // Not a machine or unit.
 
240
        return nil, common.ErrPerm
 
241
}
 
242
 
 
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) {
 
246
        if id != "" {
 
247
                // TODO: There is no direct test for this
 
248
                return nil, common.ErrBadId
 
249
        }
 
250
        return keyupdater.NewKeyUpdaterAPI(r.srv.state, r.resources, r)
 
251
}
 
252
 
 
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) {
 
256
        if id != "" {
 
257
                // TODO: There is no direct test for this
 
258
                return nil, common.ErrBadId
 
259
        }
 
260
        return charmrevisionupdater.NewCharmRevisionUpdaterAPI(r.srv.state, r.resources, r)
 
261
}
 
262
 
 
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
 
266
// in r.resources.
 
267
func (r *srvRoot) NotifyWatcher(id string) (*srvNotifyWatcher, error) {
 
268
        if err := r.requireAgent(); err != nil {
 
269
                return nil, err
 
270
        }
 
271
        watcher, ok := r.resources.Get(id).(state.NotifyWatcher)
 
272
        if !ok {
 
273
                return nil, common.ErrUnknownWatcher
 
274
        }
 
275
        return &srvNotifyWatcher{
 
276
                watcher:   watcher,
 
277
                id:        id,
 
278
                resources: r.resources,
 
279
        }, nil
 
280
}
 
281
 
 
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 {
 
287
                return nil, err
 
288
        }
 
289
        watcher, ok := r.resources.Get(id).(state.StringsWatcher)
 
290
        if !ok {
 
291
                return nil, common.ErrUnknownWatcher
 
292
        }
 
293
        return &srvStringsWatcher{
 
294
                watcher:   watcher,
 
295
                id:        id,
 
296
                resources: r.resources,
 
297
        }, nil
 
298
}
 
299
 
 
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 {
 
305
                return nil, err
 
306
        }
 
307
        watcher, ok := r.resources.Get(id).(state.RelationUnitsWatcher)
 
308
        if !ok {
 
309
                return nil, common.ErrUnknownWatcher
 
310
        }
 
311
        return &srvRelationUnitsWatcher{
 
312
                watcher:   watcher,
 
313
                id:        id,
 
314
                resources: r.resources,
 
315
        }, nil
 
316
}
 
317
 
 
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
 
321
// r.resources.
 
322
func (r *srvRoot) AllWatcher(id string) (*srvClientAllWatcher, error) {
 
323
        if err := r.requireClient(); err != nil {
 
324
                return nil, err
 
325
        }
 
326
        watcher, ok := r.resources.Get(id).(*multiwatcher.Watcher)
 
327
        if !ok {
 
328
                return nil, common.ErrUnknownWatcher
 
329
        }
 
330
        return &srvClientAllWatcher{
 
331
                watcher:   watcher,
 
332
                id:        id,
 
333
                resources: r.resources,
 
334
        }, nil
 
335
}
 
336
 
 
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
 
340
// will be dropped.
 
341
func (r *srvRoot) Pinger(id string) (pinger, error) {
 
342
        if r.pingTimeout == nil {
 
343
                return nullPinger{}, nil
 
344
        }
 
345
        return r.pingTimeout, nil
 
346
}
 
347
 
 
348
type nullPinger struct{}
 
349
 
 
350
func (nullPinger) Ping() {}
 
351
 
 
352
// AuthMachineAgent returns whether the current client is a machine agent.
 
353
func (r *srvRoot) AuthMachineAgent() bool {
 
354
        _, ok := r.entity.(*state.Machine)
 
355
        return ok
 
356
}
 
357
 
 
358
// AuthUnitAgent returns whether the current client is a unit agent.
 
359
func (r *srvRoot) AuthUnitAgent() bool {
 
360
        _, ok := r.entity.(*state.Unit)
 
361
        return ok
 
362
}
 
363
 
 
364
// AuthOwner returns whether the authenticated user's tag matches the
 
365
// given entity tag.
 
366
func (r *srvRoot) AuthOwner(tag string) bool {
 
367
        return r.entity.Tag() == tag
 
368
}
 
369
 
 
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)
 
374
}
 
375
 
 
376
// AuthClient returns whether the authenticated entity is a client
 
377
// user.
 
378
func (r *srvRoot) AuthClient() bool {
 
379
        return !isAgent(r.entity)
 
380
}
 
381
 
 
382
// GetAuthTag returns the tag of the authenticated entity.
 
383
func (r *srvRoot) GetAuthTag() string {
 
384
        return r.entity.Tag()
 
385
}
 
386
 
 
387
// GetAuthEntity returns the authenticated entity.
 
388
func (r *srvRoot) GetAuthEntity() state.Entity {
 
389
        return r.entity
 
390
}
 
391
 
 
392
// pinger describes a type that can be pinged.
 
393
type pinger interface {
 
394
        Ping()
 
395
}
 
396
 
 
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 {
 
401
        tomb    tomb.Tomb
 
402
        action  func()
 
403
        timeout time.Duration
 
404
        reset   chan struct{}
 
405
}
 
406
 
 
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 {
 
412
        pt := &pingTimeout{
 
413
                action:  action,
 
414
                timeout: timeout,
 
415
                reset:   make(chan struct{}),
 
416
        }
 
417
        go func() {
 
418
                defer pt.tomb.Done()
 
419
                pt.tomb.Kill(pt.loop())
 
420
        }()
 
421
        return pt
 
422
}
 
423
 
 
424
// Ping is used by the client heartbeat monitor and resets
 
425
// the killer.
 
426
func (pt *pingTimeout) Ping() {
 
427
        select {
 
428
        case <-pt.tomb.Dying():
 
429
        case pt.reset <- struct{}{}:
 
430
        }
 
431
}
 
432
 
 
433
// stop terminates the ping timeout.
 
434
func (pt *pingTimeout) stop() error {
 
435
        pt.tomb.Kill(nil)
 
436
        return pt.tomb.Wait()
 
437
}
 
438
 
 
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)
 
443
        defer timer.Stop()
 
444
        for {
 
445
                select {
 
446
                case <-pt.tomb.Dying():
 
447
                        return nil
 
448
                case <-timer.C:
 
449
                        go pt.action()
 
450
                        return errors.New("ping timeout")
 
451
                case <-pt.reset:
 
452
                        timer.Reset(pt.timeout)
 
453
                }
 
454
        }
 
455
}