Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2013 Canonical Ltd. | 1 // Copyright 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package apiserver | 4 package apiserver |
5 | 5 |
6 import ( | 6 import ( |
7 "time" | |
8 | |
9 "launchpad.net/tomb" | |
10 | |
7 "launchpad.net/juju-core/state" | 11 "launchpad.net/juju-core/state" |
8 "launchpad.net/juju-core/state/apiserver/agent" | 12 "launchpad.net/juju-core/state/apiserver/agent" |
9 "launchpad.net/juju-core/state/apiserver/client" | 13 "launchpad.net/juju-core/state/apiserver/client" |
10 "launchpad.net/juju-core/state/apiserver/common" | 14 "launchpad.net/juju-core/state/apiserver/common" |
11 "launchpad.net/juju-core/state/apiserver/deployer" | 15 "launchpad.net/juju-core/state/apiserver/deployer" |
12 loggerapi "launchpad.net/juju-core/state/apiserver/logger" | 16 loggerapi "launchpad.net/juju-core/state/apiserver/logger" |
13 "launchpad.net/juju-core/state/apiserver/machine" | 17 "launchpad.net/juju-core/state/apiserver/machine" |
14 "launchpad.net/juju-core/state/apiserver/provisioner" | 18 "launchpad.net/juju-core/state/apiserver/provisioner" |
15 "launchpad.net/juju-core/state/apiserver/uniter" | 19 "launchpad.net/juju-core/state/apiserver/uniter" |
16 "launchpad.net/juju-core/state/apiserver/upgrader" | 20 "launchpad.net/juju-core/state/apiserver/upgrader" |
17 "launchpad.net/juju-core/state/multiwatcher" | 21 "launchpad.net/juju-core/state/multiwatcher" |
18 ) | 22 ) |
19 | 23 |
20 type clientAPI struct{ *client.API } | 24 type clientAPI struct{ *client.API } |
21 | 25 |
22 type taggedAuthenticator interface { | 26 type taggedAuthenticator interface { |
23 state.Entity | 27 state.Entity |
24 state.Authenticator | 28 state.Authenticator |
25 } | 29 } |
26 | 30 |
27 // srvRoot represents a single client's connection to the state | 31 // srvRoot represents a single client's connection to the state |
28 // after it has logged in. | 32 // after it has logged in. |
29 type srvRoot struct { | 33 type srvRoot struct { |
30 clientAPI | 34 clientAPI |
31 » srv *Server | 35 » initialRoot *initialRoot |
32 » resources *common.Resources | 36 » resources *common.Resources |
37 » pingTimeout *pingTimeout | |
33 | 38 |
34 entity taggedAuthenticator | 39 entity taggedAuthenticator |
35 } | 40 } |
36 | 41 |
37 func newSrvRoot(srv *Server, entity taggedAuthenticator) *srvRoot { | 42 func newSrvRoot(root *initialRoot, entity taggedAuthenticator) *srvRoot { |
38 r := &srvRoot{ | 43 r := &srvRoot{ |
39 » » srv: srv, | 44 » » initialRoot: root, |
rog
2013/11/18 18:19:48
Rather than having initialRoot inside srvRoot, I'd
mue
2013/11/19 13:50:46
Done.
| |
40 » » resources: common.NewResources(), | 45 » » resources: common.NewResources(), |
41 » » entity: entity, | 46 » » entity: entity, |
42 } | 47 } |
43 » r.clientAPI.API = client.NewAPI(srv.state, r.resources, r) | 48 » action := func() error { |
49 » » return r.initialRoot.rpcConn.Close() | |
50 » } | |
51 » r.clientAPI.API = client.NewAPI(root.srv.state, r.resources, r) | |
52 » r.pingTimeout = newPingTimeout(r.entity.Tag(), action, 3*time.Minute) | |
rog
2013/11/18 18:19:48
There's nothing that cleans this up when the conne
mue
2013/11/19 13:50:46
Yep, cleanup has been prepared but led to the dead
| |
44 return r | 53 return r |
45 } | 54 } |
46 | 55 |
47 // Kill implements rpc.Killer. It cleans up any resources that need | 56 // Kill implements rpc.Killer. It cleans up any resources that need |
48 // cleaning up to ensure that all outstanding requests return. | 57 // cleaning up to ensure that all outstanding requests return. |
49 func (r *srvRoot) Kill() { | 58 func (r *srvRoot) Kill() { |
50 r.resources.StopAll() | 59 r.resources.StopAll() |
51 } | 60 } |
52 | 61 |
53 // requireAgent checks whether the current client is an agent and hence | 62 // requireAgent checks whether the current client is an agent and hence |
(...skipping 17 matching lines...) Expand all Loading... | |
71 } | 80 } |
72 | 81 |
73 // Machiner returns an object that provides access to the Machiner API | 82 // Machiner returns an object that provides access to the Machiner API |
74 // facade. The id argument is reserved for future use and currently | 83 // facade. The id argument is reserved for future use and currently |
75 // needs to be empty. | 84 // needs to be empty. |
76 func (r *srvRoot) Machiner(id string) (*machine.MachinerAPI, error) { | 85 func (r *srvRoot) Machiner(id string) (*machine.MachinerAPI, error) { |
77 if id != "" { | 86 if id != "" { |
78 // Safeguard id for possible future use. | 87 // Safeguard id for possible future use. |
79 return nil, common.ErrBadId | 88 return nil, common.ErrBadId |
80 } | 89 } |
81 » return machine.NewMachinerAPI(r.srv.state, r.resources, r) | 90 » return machine.NewMachinerAPI(r.initialRoot.srv.state, r.resources, r) |
82 } | 91 } |
83 | 92 |
84 // Provisioner returns an object that provides access to the | 93 // Provisioner returns an object that provides access to the |
85 // Provisioner API facade. The id argument is reserved for future use | 94 // Provisioner API facade. The id argument is reserved for future use |
86 // and currently needs to be empty. | 95 // and currently needs to be empty. |
87 func (r *srvRoot) Provisioner(id string) (*provisioner.ProvisionerAPI, error) { | 96 func (r *srvRoot) Provisioner(id string) (*provisioner.ProvisionerAPI, error) { |
88 if id != "" { | 97 if id != "" { |
89 // Safeguard id for possible future use. | 98 // Safeguard id for possible future use. |
90 return nil, common.ErrBadId | 99 return nil, common.ErrBadId |
91 } | 100 } |
92 » return provisioner.NewProvisionerAPI(r.srv.state, r.resources, r) | 101 » return provisioner.NewProvisionerAPI(r.initialRoot.srv.state, r.resource s, r) |
93 } | 102 } |
94 | 103 |
95 // MachineAgent returns an object that provides access to the machine | 104 // MachineAgent returns an object that provides access to the machine |
96 // agent API. The id argument is reserved for future use and must currently | 105 // agent API. The id argument is reserved for future use and must currently |
97 // be empty. | 106 // be empty. |
98 // DEPRECATED(v1.14) | 107 // DEPRECATED(v1.14) |
99 func (r *srvRoot) MachineAgent(id string) (*machine.AgentAPI, error) { | 108 func (r *srvRoot) MachineAgent(id string) (*machine.AgentAPI, error) { |
100 if id != "" { | 109 if id != "" { |
101 return nil, common.ErrBadId | 110 return nil, common.ErrBadId |
102 } | 111 } |
103 » return machine.NewAgentAPI(r.srv.state, r) | 112 » return machine.NewAgentAPI(r.initialRoot.srv.state, r) |
104 } | 113 } |
105 | 114 |
106 // Uniter returns an object that provides access to the Uniter API | 115 // Uniter returns an object that provides access to the Uniter API |
107 // facade. The id argument is reserved for future use and currently | 116 // facade. The id argument is reserved for future use and currently |
108 // needs to be empty. | 117 // needs to be empty. |
109 func (r *srvRoot) Uniter(id string) (*uniter.UniterAPI, error) { | 118 func (r *srvRoot) Uniter(id string) (*uniter.UniterAPI, error) { |
110 if id != "" { | 119 if id != "" { |
111 // Safeguard id for possible future use. | 120 // Safeguard id for possible future use. |
112 return nil, common.ErrBadId | 121 return nil, common.ErrBadId |
113 } | 122 } |
114 » return uniter.NewUniterAPI(r.srv.state, r.resources, r) | 123 » return uniter.NewUniterAPI(r.initialRoot.srv.state, r.resources, r) |
115 } | 124 } |
116 | 125 |
117 // Agent returns an object that provides access to the | 126 // Agent returns an object that provides access to the |
118 // agent API. The id argument is reserved for future use and must currently | 127 // agent API. The id argument is reserved for future use and must currently |
119 // be empty. | 128 // be empty. |
120 func (r *srvRoot) Agent(id string) (*agent.API, error) { | 129 func (r *srvRoot) Agent(id string) (*agent.API, error) { |
121 if id != "" { | 130 if id != "" { |
122 return nil, common.ErrBadId | 131 return nil, common.ErrBadId |
123 } | 132 } |
124 » return agent.NewAPI(r.srv.state, r) | 133 » return agent.NewAPI(r.initialRoot.srv.state, r) |
125 } | 134 } |
126 | 135 |
127 // Deployer returns an object that provides access to the Deployer API facade. | 136 // Deployer returns an object that provides access to the Deployer API facade. |
128 // The id argument is reserved for future use and must be empty. | 137 // The id argument is reserved for future use and must be empty. |
129 func (r *srvRoot) Deployer(id string) (*deployer.DeployerAPI, error) { | 138 func (r *srvRoot) Deployer(id string) (*deployer.DeployerAPI, error) { |
130 if id != "" { | 139 if id != "" { |
131 // TODO(dimitern): There is no direct test for this | 140 // TODO(dimitern): There is no direct test for this |
132 return nil, common.ErrBadId | 141 return nil, common.ErrBadId |
133 } | 142 } |
134 » return deployer.NewDeployerAPI(r.srv.state, r.resources, r) | 143 » return deployer.NewDeployerAPI(r.initialRoot.srv.state, r.resources, r) |
135 } | 144 } |
136 | 145 |
137 // Logger returns an object that provides access to the Logger API facade. | 146 // Logger returns an object that provides access to the Logger API facade. |
138 // The id argument is reserved for future use and must be empty. | 147 // The id argument is reserved for future use and must be empty. |
139 func (r *srvRoot) Logger(id string) (*loggerapi.LoggerAPI, error) { | 148 func (r *srvRoot) Logger(id string) (*loggerapi.LoggerAPI, error) { |
140 if id != "" { | 149 if id != "" { |
141 // TODO: There is no direct test for this | 150 // TODO: There is no direct test for this |
142 return nil, common.ErrBadId | 151 return nil, common.ErrBadId |
143 } | 152 } |
144 » return loggerapi.NewLoggerAPI(r.srv.state, r.resources, r) | 153 » return loggerapi.NewLoggerAPI(r.initialRoot.srv.state, r.resources, r) |
145 } | 154 } |
146 | 155 |
147 // Upgrader returns an object that provides access to the Upgrader API facade. | 156 // Upgrader returns an object that provides access to the Upgrader API facade. |
148 // The id argument is reserved for future use and must be empty. | 157 // The id argument is reserved for future use and must be empty. |
149 func (r *srvRoot) Upgrader(id string) (*upgrader.UpgraderAPI, error) { | 158 func (r *srvRoot) Upgrader(id string) (*upgrader.UpgraderAPI, error) { |
150 if id != "" { | 159 if id != "" { |
151 // TODO: There is no direct test for this | 160 // TODO: There is no direct test for this |
152 return nil, common.ErrBadId | 161 return nil, common.ErrBadId |
153 } | 162 } |
154 » return upgrader.NewUpgraderAPI(r.srv.state, r.resources, r) | 163 » return upgrader.NewUpgraderAPI(r.initialRoot.srv.state, r.resources, r) |
155 } | 164 } |
156 | 165 |
157 // NotifyWatcher returns an object that provides | 166 // NotifyWatcher returns an object that provides |
158 // API access to methods on a state.NotifyWatcher. | 167 // API access to methods on a state.NotifyWatcher. |
159 // Each client has its own current set of watchers, stored | 168 // Each client has its own current set of watchers, stored |
160 // in r.resources. | 169 // in r.resources. |
161 func (r *srvRoot) NotifyWatcher(id string) (*srvNotifyWatcher, error) { | 170 func (r *srvRoot) NotifyWatcher(id string) (*srvNotifyWatcher, error) { |
162 if err := r.requireAgent(); err != nil { | 171 if err := r.requireAgent(); err != nil { |
163 return nil, err | 172 return nil, err |
164 } | 173 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 if !ok { | 230 if !ok { |
222 return nil, common.ErrUnknownWatcher | 231 return nil, common.ErrUnknownWatcher |
223 } | 232 } |
224 return &srvClientAllWatcher{ | 233 return &srvClientAllWatcher{ |
225 watcher: watcher, | 234 watcher: watcher, |
226 id: id, | 235 id: id, |
227 resources: r.resources, | 236 resources: r.resources, |
228 }, nil | 237 }, nil |
229 } | 238 } |
230 | 239 |
231 // Pinger returns object with a single "Ping" method that does nothing. | 240 // Pinger returns a server pinger tracing the client pings and |
rog
2013/11/18 18:19:48
// Pinger returns an object that can be pinged
//
mue
2013/11/19 13:50:46
Done.
| |
232 func (r *srvRoot) Pinger(id string) (srvPinger, error) { | 241 // terminating the root after 3 minutes with no pings. |
233 » return srvPinger{}, nil | 242 func (r *srvRoot) Pinger(id string) (pinger, error) { |
243 » return r.pingTimeout, nil | |
234 } | 244 } |
235 | 245 |
236 type srvPinger struct{} | |
237 | |
238 // Ping is a no-op used by client heartbeat monitor. | |
239 func (r srvPinger) Ping() {} | |
240 | |
241 // AuthMachineAgent returns whether the current client is a machine agent. | 246 // AuthMachineAgent returns whether the current client is a machine agent. |
242 func (r *srvRoot) AuthMachineAgent() bool { | 247 func (r *srvRoot) AuthMachineAgent() bool { |
243 _, ok := r.entity.(*state.Machine) | 248 _, ok := r.entity.(*state.Machine) |
244 return ok | 249 return ok |
245 } | 250 } |
246 | 251 |
247 // AuthUnitAgent returns whether the current client is a unit agent. | 252 // AuthUnitAgent returns whether the current client is a unit agent. |
248 func (r *srvRoot) AuthUnitAgent() bool { | 253 func (r *srvRoot) AuthUnitAgent() bool { |
249 _, ok := r.entity.(*state.Unit) | 254 _, ok := r.entity.(*state.Unit) |
250 return ok | 255 return ok |
(...skipping 19 matching lines...) Expand all Loading... | |
270 | 275 |
271 // GetAuthTag returns the tag of the authenticated entity. | 276 // GetAuthTag returns the tag of the authenticated entity. |
272 func (r *srvRoot) GetAuthTag() string { | 277 func (r *srvRoot) GetAuthTag() string { |
273 return r.entity.Tag() | 278 return r.entity.Tag() |
274 } | 279 } |
275 | 280 |
276 // GetAuthEntity returns the authenticated entity. | 281 // GetAuthEntity returns the authenticated entity. |
277 func (r *srvRoot) GetAuthEntity() state.Entity { | 282 func (r *srvRoot) GetAuthEntity() state.Entity { |
278 return r.entity | 283 return r.entity |
279 } | 284 } |
285 | |
286 // pinger describes a type that can be pinged. | |
287 type pinger interface { | |
288 Ping() | |
289 } | |
290 | |
291 // pingTimeout listens for pings and will call the | |
292 // passed action in case of a timeout. This way broken | |
293 // or inactive connections can be closed. | |
294 type pingTimeout struct { | |
295 tomb tomb.Tomb | |
296 tag string | |
rog
2013/11/18 18:19:48
Do we need the tag here?
mue
2013/11/19 13:50:46
Removed, I only needed it during testing.
| |
297 action func() error | |
298 timeout time.Duration | |
299 reset chan struct{} | |
300 } | |
301 | |
302 // newPingTimeout creates a ping timeout instance | |
rog
2013/11/18 18:19:48
// newPingTimeout returns a new pingTimeout instan
mue
2013/11/19 13:50:46
Done.
| |
303 // for the passed action and timeout. | |
304 func newPingTimeout(tag string, action func() error, timeout time.Duration) *pin gTimeout { | |
305 pt := &pingTimeout{ | |
306 tag: tag, | |
307 action: action, | |
308 timeout: timeout, | |
309 reset: make(chan struct{}), | |
310 } | |
311 go func() { | |
rog
2013/11/18 18:19:48
I *think* that if you do:
defer action()
here
mue
2013/11/19 13:50:46
Done.
| |
312 defer pt.tomb.Done() | |
313 pt.tomb.Kill(pt.loop()) | |
314 }() | |
315 return pt | |
316 } | |
317 | |
318 // Ping is used by the client heartbeat monitor and resets | |
319 // the killer. | |
320 func (pt *pingTimeout) Ping() { | |
321 select { | |
322 case <-pt.tomb.Dying(): | |
323 case pt.reset <- struct{}{}: | |
324 } | |
325 } | |
326 | |
327 // stop terminates the resource timeout. | |
328 func (pt *pingTimeout) stop() error { | |
rog
2013/11/18 18:19:48
I don't think this is ever called.
mue
2013/11/19 13:50:46
No it's done, it already had been intended for the
| |
329 pt.tomb.Kill(nil) | |
330 return pt.tomb.Wait() | |
331 } | |
332 | |
333 // loop waits for a reset signal, otherwise it performs | |
334 // the initially passed action. | |
335 func (pt *pingTimeout) loop() error { | |
336 timer := time.NewTimer(pt.timeout) | |
337 defer timer.Stop() | |
338 for { | |
339 select { | |
340 case <-pt.tomb.Dying(): | |
341 return nil | |
342 case <-timer.C: | |
343 return pt.action() | |
344 case <-pt.reset: | |
345 timer.Reset(pt.timeout) | |
346 } | |
347 } | |
348 } | |
OLD | NEW |