Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(334)

Delta Between Two Patch Sets: state/api/apiserver.go

Issue 7390043: state/api: implement machine watching
Left Patch Set: state/api: implement machine watching Created 12 years, 1 month ago
Right Patch Set: state/api: implement machine watching Created 12 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « state/api/apiclient.go ('k') | state/api/client.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 package api 1 package api
2 2
3 import ( 3 import (
4 "code.google.com/p/go.net/websocket" 4 "code.google.com/p/go.net/websocket"
5 "fmt" 5 "fmt"
6 "launchpad.net/juju-core/log"
6 "launchpad.net/juju-core/state" 7 "launchpad.net/juju-core/state"
8 "launchpad.net/juju-core/state/statecmd"
7 statewatcher "launchpad.net/juju-core/state/watcher" 9 statewatcher "launchpad.net/juju-core/state/watcher"
8 "strconv" 10 "strconv"
9 "sync" 11 "sync"
10 ) 12 )
11 13
12 // TODO(rog) remove this when the rest of the system 14 // TODO(rog) remove this when the rest of the system
13 // has been updated to set passwords appropriately. 15 // has been updated to set passwords appropriately.
14 var AuthenticationEnabled = false 16 var AuthenticationEnabled = false
15 17
16 // srvRoot represents a single client's connection to the state. 18 // srvRoot represents a single client's connection to the state.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 } 64 }
63 r.admin = &srvAdmin{ 65 r.admin = &srvAdmin{
64 root: r, 66 root: r,
65 } 67 }
66 r.client = &srvClient{ 68 r.client = &srvClient{
67 root: r, 69 root: r,
68 } 70 }
69 return r 71 return r
70 } 72 }
71 73
74 // Kill implements rpc.Killer. It cleans up any resources that need
75 // cleaning up to ensure that all outstanding requests return.
76 func (r *srvRoot) Kill() {
77 r.watchers.stopAll()
78 }
79
80 // Admin returns an object that provides API access
81 // to methods that can be called even when not
82 // authenticated.
72 func (r *srvRoot) Admin(id string) (*srvAdmin, error) { 83 func (r *srvRoot) Admin(id string) (*srvAdmin, error) {
73 if id != "" { 84 if id != "" {
74 // Safeguard id for possible future use. 85 // Safeguard id for possible future use.
75 return nil, errBadId 86 return nil, errBadId
76 } 87 }
77 return r.admin, nil 88 return r.admin, nil
78 } 89 }
79 90
80 // requireAgent checks whether the current client is an agent and hence 91 // requireAgent checks whether the current client is an agent and hence
81 // may access the agent APIs. We filter out non-agents when calling one 92 // may access the agent APIs. We filter out non-agents when calling one
(...skipping 16 matching lines...) Expand all
98 e := r.user.entity() 109 e := r.user.entity()
99 if e == nil { 110 if e == nil {
100 return errNotLoggedIn 111 return errNotLoggedIn
101 } 112 }
102 if isAgent(e) { 113 if isAgent(e) {
103 return errPerm 114 return errPerm
104 } 115 }
105 return nil 116 return nil
106 } 117 }
107 118
119 // Machine returns an object that provides
120 // API access to methods on a state.Machine.
108 func (r *srvRoot) Machine(id string) (*srvMachine, error) { 121 func (r *srvRoot) Machine(id string) (*srvMachine, error) {
109 if err := r.requireAgent(); err != nil { 122 if err := r.requireAgent(); err != nil {
110 return nil, err 123 return nil, err
111 } 124 }
112 m, err := r.srv.state.Machine(id) 125 m, err := r.srv.state.Machine(id)
113 if err != nil { 126 if err != nil {
114 return nil, err 127 return nil, err
115 } 128 }
116 return &srvMachine{ 129 return &srvMachine{
117 root: r, 130 root: r,
118 m: m, 131 m: m,
119 }, nil 132 }, nil
120 } 133 }
121 134
135 // Unit returns an object that provides
136 // API access to methods on a state.Unit.
122 func (r *srvRoot) Unit(name string) (*srvUnit, error) { 137 func (r *srvRoot) Unit(name string) (*srvUnit, error) {
123 if err := r.requireAgent(); err != nil { 138 if err := r.requireAgent(); err != nil {
124 return nil, err 139 return nil, err
125 } 140 }
126 u, err := r.srv.state.Unit(name) 141 u, err := r.srv.state.Unit(name)
127 if err != nil { 142 if err != nil {
128 return nil, err 143 return nil, err
129 } 144 }
130 return &srvUnit{ 145 return &srvUnit{
131 root: r, 146 root: r,
132 u: u, 147 u: u,
133 }, nil 148 }, nil
134 } 149 }
135 150
151 // User returns an object that provides
152 // API access to methods on a state.User.
136 func (r *srvRoot) User(name string) (*srvUser, error) { 153 func (r *srvRoot) User(name string) (*srvUser, error) {
137 // Any user is allowed to access their own user object. 154 // Any user is allowed to access their own user object.
138 // We check at this level rather than at the operation 155 // We check at this level rather than at the operation
139 // level to stop malicious probing for current user names. 156 // level to stop malicious probing for current user names.
140 // When we provide support for user administration, 157 // When we provide support for user administration,
141 // this will need to be changed to allow access to 158 // this will need to be changed to allow access to
142 // the administrator. 159 // the administrator.
143 e := r.user.entity() 160 e := r.user.entity()
144 if e == nil { 161 if e == nil {
145 return nil, errNotLoggedIn 162 return nil, errNotLoggedIn
146 } 163 }
147 if e.EntityName() != name { 164 if e.EntityName() != name {
148 return nil, errPerm 165 return nil, errPerm
149 } 166 }
150 u, err := r.srv.state.User(name) 167 u, err := r.srv.state.User(name)
151 if err != nil { 168 if err != nil {
152 return nil, err 169 return nil, err
153 } 170 }
154 return &srvUser{ 171 return &srvUser{
155 root: r, 172 root: r,
156 u: u, 173 u: u,
157 }, nil 174 }, nil
158 } 175 }
159 176
177 // EntityWatcher returns an object that provides
178 // API access to methods on a state.EntityWatcher.
179 // Each client has its own current set of watchers, stored
180 // in r.watchers.
160 func (r *srvRoot) EntityWatcher(id string) (srvEntityWatcher, error) { 181 func (r *srvRoot) EntityWatcher(id string) (srvEntityWatcher, error) {
dimitern 2013/02/21 11:23:29 Comment here please?
fwereade 2013/02/25 09:03:43 +1
rog 2013/02/25 10:50:00 done. added comments to some other methods too.
fwereade 2013/02/25 11:24:13 <3
161 if err := r.requireAgent(); err != nil { 182 if err := r.requireAgent(); err != nil {
162 return srvEntityWatcher{}, err 183 return srvEntityWatcher{}, err
163 } 184 }
164 w := r.watchers.get(id) 185 w := r.watchers.get(id)
165 if w == nil { 186 if w == nil {
166 return srvEntityWatcher{}, errUnknownWatcher 187 return srvEntityWatcher{}, errUnknownWatcher
167 } 188 }
168 if _, ok := w.w.(*state.EntityWatcher); !ok { 189 if _, ok := w.w.(*state.EntityWatcher); !ok {
169 return srvEntityWatcher{}, errUnknownWatcher 190 return srvEntityWatcher{}, errUnknownWatcher
170 } 191 }
171 return srvEntityWatcher{w}, nil 192 return srvEntityWatcher{w}, nil
172 } 193 }
173 194
195 // Client returns an object that provides access
196 // to methods accessible to non-agent clients.
197 func (r *srvRoot) Client(id string) (*srvClient, error) {
198 if err := r.requireClient(); err != nil {
199 return nil, err
200 }
201 if id != "" {
202 // Safeguard id for possible future use.
203 return nil, errBadId
204 }
205 return r.client, nil
206 }
207
174 type srvEntityWatcher struct { 208 type srvEntityWatcher struct {
175 *srvWatcher 209 *srvWatcher
176 } 210 }
177 211
212 // Next returns when a change has occurred to the
213 // entity being watched since the most recent call to Next
214 // or the Watch call that created the EntityWatcher.
178 func (w srvEntityWatcher) Next() error { 215 func (w srvEntityWatcher) Next() error {
179 if _, ok := <-w.w.(*state.EntityWatcher).Changes(); ok { 216 if _, ok := <-w.w.(*state.EntityWatcher).Changes(); ok {
180 return nil 217 return nil
181 } 218 }
182 err := w.w.Err() 219 err := w.w.Err()
183 if err == nil { 220 if err == nil {
184 err = errStoppedWatcher 221 err = errStoppedWatcher
185 } 222 }
186 return err 223 return err
187 }
188
189 func (r *srvRoot) Client(id string) (*srvClient, error) {
190 if err := r.requireClient(); err != nil {
191 return nil, err
192 }
193 if id != "" {
194 // Safeguard id for possible future use.
195 return nil, errBadId
196 }
197 return r.client, nil
198 } 224 }
199 225
200 func (c *srvClient) Status() (Status, error) { 226 func (c *srvClient) Status() (Status, error) {
201 ms, err := c.root.srv.state.AllMachines() 227 ms, err := c.root.srv.state.AllMachines()
202 if err != nil { 228 if err != nil {
203 return Status{}, err 229 return Status{}, err
204 } 230 }
205 status := Status{ 231 status := Status{
206 Machines: make(map[string]MachineInfo), 232 Machines: make(map[string]MachineInfo),
207 } 233 }
208 for _, m := range ms { 234 for _, m := range ms {
209 instId, _ := m.InstanceId() 235 instId, _ := m.InstanceId()
210 status.Machines[m.Id()] = MachineInfo{ 236 status.Machines[m.Id()] = MachineInfo{
211 InstanceId: string(instId), 237 InstanceId: string(instId),
212 } 238 }
213 } 239 }
214 return status, nil 240 return status, nil
241 }
242
243 // ServiceSet implements the server side of Client.ServerSet.
244 func (c *srvClient) ServiceSet(p statecmd.ServiceSetParams) error {
245 return statecmd.ServiceSet(c.root.srv.state, p)
246 }
247
248 // ServiceSetYAML implements the server side of Client.ServerSetYAML.
249 func (c *srvClient) ServiceSetYAML(p statecmd.ServiceSetYAMLParams) error {
250 return statecmd.ServiceSetYAML(c.root.srv.state, p)
251 }
252
253 func (c *srvClient) ServiceGet(args statecmd.ServiceGetParams) (statecmd.Service GetResults, error) {
254 return statecmd.ServiceGet(c.root.srv.state, args)
255 }
256
257 // EnvironmentInfo returns information about the current environment (default
258 // series and type).
259 func (c *srvClient) EnvironmentInfo() (EnvironmentInfo, error) {
260 conf, err := c.root.srv.state.EnvironConfig()
261 if err != nil {
262 return EnvironmentInfo{}, err
263 }
264 info := EnvironmentInfo{
265 DefaultSeries: conf.DefaultSeries(),
266 ProviderType: conf.Type(),
267 }
268 return info, nil
215 } 269 }
216 270
217 type rpcCreds struct { 271 type rpcCreds struct {
218 EntityName string 272 EntityName string
219 Password string 273 Password string
220 } 274 }
221 275
222 // Login logs in with the provided credentials. 276 // Login logs in with the provided credentials.
223 // All subsequent requests on the connection will 277 // All subsequent requests on the connection will
224 // act as the authenticated user. 278 // act as the authenticated user.
(...skipping 24 matching lines...) Expand all
249 return rpcEntityWatcherId{ 303 return rpcEntityWatcherId{
250 EntityWatcherId: m.root.watchers.register(w).id, 304 EntityWatcherId: m.root.watchers.register(w).id,
251 }, nil 305 }, nil
252 } 306 }
253 307
254 type rpcPassword struct { 308 type rpcPassword struct {
255 Password string 309 Password string
256 } 310 }
257 311
258 func setPassword(e state.AuthEntity, password string) error { 312 func setPassword(e state.AuthEntity, password string) error {
259 // Catch expected common case of mispelled 313 // Catch expected common case of mispelled
dimitern 2013/02/21 11:23:29 why misspelled? it only checks for empty one.
rog 2013/02/25 10:50:00 if the caller sends a message with a field named "
260 // or missing Password parameter. 314 // or missing Password parameter.
261 if password == "" { 315 if password == "" {
262 return fmt.Errorf("password is empty") 316 return fmt.Errorf("password is empty")
263 } 317 }
264 return e.SetPassword(password) 318 return e.SetPassword(password)
265 } 319 }
266 320
267 // SetPassword sets the machine's password. 321 // SetPassword sets the machine's password.
268 func (m *srvMachine) SetPassword(p rpcPassword) error { 322 func (m *srvMachine) SetPassword(p rpcPassword) error {
269 // Allow: 323 // Allow:
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 } 433 }
380 return false 434 return false
381 } 435 }
382 436
383 // isAgent returns whether the given entity is an agent. 437 // isAgent returns whether the given entity is an agent.
384 func isAgent(e state.AuthEntity) bool { 438 func isAgent(e state.AuthEntity) bool {
385 _, isUser := e.(*state.User) 439 _, isUser := e.(*state.User)
386 return !isUser 440 return !isUser
387 } 441 }
388 442
443 // watcher represents the interface provided by state watchers.
389 type watcher interface { 444 type watcher interface {
390 Stop() error 445 Stop() error
391 Err() error 446 Err() error
dimitern 2013/02/21 11:23:29 Is there a special reason no to implement Error()
fwereade 2013/02/25 09:03:43 Eww! Please don't do that. They're totally differe
rog 2013/02/25 10:50:00 this interface reflects the existing interface com
392 } 447 }
393 448
394 // watchers holds all the watchers for a connection. 449 // watchers holds all the watchers for a connection.
395 type watchers struct { 450 type watchers struct {
396 mu sync.Mutex 451 mu sync.Mutex
397 maxId uint64 452 maxId uint64
398 ws map[string]*srvWatcher 453 ws map[string]*srvWatcher
399 } 454 }
400 455
401 // srvWatcher holds the details of a watcher. 456 // srvWatcher holds the details of a watcher. It also implements the
402 // It also implements the Stop RPC method 457 // Stop RPC method for all watchers.
403 // for all watchers.
404 type srvWatcher struct { 458 type srvWatcher struct {
405 ws *watchers 459 ws *watchers
406 w watcher 460 w watcher
407 id string 461 id string
408 } 462 }
409 463
464 // Stop stops the given watcher. It causes any outstanding
465 // Next calls to return a CodeStopped error.
466 // Any subsequent Next calls will return a CodeNotFound
467 // error because the watcher will no longer exist.
410 func (w *srvWatcher) Stop() error { 468 func (w *srvWatcher) Stop() error {
411 err := w.w.Stop() 469 err := w.w.Stop()
412 w.ws.mu.Lock() 470 w.ws.mu.Lock()
413 defer w.ws.mu.Unlock() 471 defer w.ws.mu.Unlock()
414 delete(w.ws.ws, w.id) 472 delete(w.ws.ws, w.id)
415 return err 473 return err
416 } 474 }
417 475
418 func newWatchers() *watchers { 476 func newWatchers() *watchers {
419 return &watchers{ 477 return &watchers{
(...skipping 16 matching lines...) Expand all
436 defer ws.mu.Unlock() 494 defer ws.mu.Unlock()
437 ws.maxId++ 495 ws.maxId++
438 sw := &srvWatcher{ 496 sw := &srvWatcher{
439 ws: ws, 497 ws: ws,
440 id: strconv.FormatUint(ws.maxId, 10), 498 id: strconv.FormatUint(ws.maxId, 10),
441 w: w, 499 w: w,
442 } 500 }
443 ws.ws[sw.id] = sw 501 ws.ws[sw.id] = sw
444 return sw 502 return sw
445 } 503 }
504
505 func (ws *watchers) stopAll() {
506 ws.mu.Lock()
507 defer ws.mu.Unlock()
508 for _, w := range ws.ws {
509 if err := w.w.Stop(); err != nil {
510 log.Printf("state/api: error stopping %T watcher: %v", w , err)
511 }
512 }
513 ws.ws = make(map[string]*srvWatcher)
514 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b