LEFT | RIGHT |
1 // The state package enables reading, observing, and changing | 1 // The state package enables reading, observing, and changing |
2 // the state stored in ZooKeeper of a whole environment | 2 // the state stored in ZooKeeper of a whole environment |
3 // managed by juju. | 3 // managed by juju. |
4 package state | 4 package state |
5 | 5 |
6 import ( | 6 import ( |
7 "fmt" | 7 "fmt" |
8 "launchpad.net/goyaml" | 8 "launchpad.net/goyaml" |
9 "launchpad.net/gozk/zookeeper" | 9 "launchpad.net/gozk/zookeeper" |
10 "launchpad.net/juju/go/charm" | 10 "launchpad.net/juju/go/charm" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 | 65 |
66 // WatchMachines watches for new Machines added or removed. | 66 // WatchMachines watches for new Machines added or removed. |
67 func (s *State) WatchMachines() *MachinesWatcher { | 67 func (s *State) WatchMachines() *MachinesWatcher { |
68 return newMachinesWatcher(s) | 68 return newMachinesWatcher(s) |
69 } | 69 } |
70 | 70 |
71 // WatchEnvironConfig returns a watcher for observing | 71 // WatchEnvironConfig returns a watcher for observing |
72 // changes to the environment configuration. | 72 // changes to the environment configuration. |
73 func (s *State) WatchEnvironConfig() *ConfigWatcher { | 73 func (s *State) WatchEnvironConfig() *ConfigWatcher { |
74 return newConfigWatcher(s, zkEnvironmentPath) | 74 return newConfigWatcher(s, zkEnvironmentPath) |
| 75 } |
| 76 |
| 77 // Environment returns the current configuration of the environment. |
| 78 func (s *State) Environment() (*ConfigNode, error) { |
| 79 return readConfigNode(s.zk, zkEnvironmentPath) |
75 } | 80 } |
76 | 81 |
77 // Machine returns the machine with the given id. | 82 // Machine returns the machine with the given id. |
78 func (s *State) Machine(id int) (*Machine, error) { | 83 func (s *State) Machine(id int) (*Machine, error) { |
79 key := machineKey(id) | 84 key := machineKey(id) |
80 topology, err := readTopology(s.zk) | 85 topology, err := readTopology(s.zk) |
81 if err != nil { | 86 if err != nil { |
82 return nil, err | 87 return nil, err |
83 } | 88 } |
84 if !topology.HasMachine(key) { | 89 if !topology.HasMachine(key) { |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 | 258 |
254 // addRelationNode creates the relation node. | 259 // addRelationNode creates the relation node. |
255 func (s *State) addRelationNode(scope RelationScope) (string, error) { | 260 func (s *State) addRelationNode(scope RelationScope) (string, error) { |
256 path, err := s.zk.Create("/relations/relation-", "", zookeeper.SEQUENCE,
zkPermAll) | 261 path, err := s.zk.Create("/relations/relation-", "", zookeeper.SEQUENCE,
zkPermAll) |
257 if err != nil { | 262 if err != nil { |
258 return "", err | 263 return "", err |
259 } | 264 } |
260 relationKey := strings.Split(path, "/")[2] | 265 relationKey := strings.Split(path, "/")[2] |
261 // Create the settings node only if the scope is global. | 266 // Create the settings node only if the scope is global. |
262 // In case of container scoped relations the creation per | 267 // In case of container scoped relations the creation per |
263 » // container occurs in ServiceRelation.AddUnit(). | 268 » // container occurs in ServiceRelation.AddUnit. |
264 if scope == ScopeGlobal { | 269 if scope == ScopeGlobal { |
265 _, err = s.zk.Create(path+"/settings", "", 0, zkPermAll) | 270 _, err = s.zk.Create(path+"/settings", "", 0, zkPermAll) |
266 if err != nil { | 271 if err != nil { |
267 return "", err | 272 return "", err |
268 } | 273 } |
269 } | 274 } |
270 return relationKey, nil | 275 return relationKey, nil |
271 } | 276 } |
272 | 277 |
273 // addRelationEndpointNode creates the endpoint role node below its relation nod
e· | 278 // addRelationEndpointNode creates the endpoint role node below its relation nod
e· |
274 // for the given relation endpoint. | 279 // for the given relation endpoint. |
275 func (s *State) addRelationEndpointNode(relationKey string, endpoint RelationEnd
point, scope RelationScope) error { | 280 func (s *State) addRelationEndpointNode(relationKey string, endpoint RelationEnd
point) error { |
276 » // Create the role node only if the scope is global. | 281 » path := fmt.Sprintf("/relations/%s/%s", relationKey, string(endpoint.Rel
ationRole)) |
277 » // In case of container scoped relations the creation· | 282 » _, err := s.zk.Create(path, "", 0, zkPermAll) |
278 » // per container occurs in ServiceRelation.AddUnit(). | 283 » return err |
279 » if scope == ScopeGlobal { | |
280 » » path := fmt.Sprintf("/relations/%s/%s", relationKey, string(endp
oint.RelationRole)) | |
281 » » _, err := s.zk.Create(path, "", 0, zkPermAll) | |
282 » » if err != nil { | |
283 » » » return err | |
284 » » } | |
285 » } | |
286 » return nil | |
287 } | 284 } |
288 | 285 |
289 // AddRelation creates a new relation with the given endpoints.·· | 286 // AddRelation creates a new relation with the given endpoints.·· |
290 func (s *State) AddRelation(endpoints ...RelationEndpoint) (*Relation, []*Servic
eRelation, error) { | 287 func (s *State) AddRelation(endpoints ...RelationEndpoint) (*Relation, []*Servic
eRelation, error) { |
291 switch len(endpoints) { | 288 switch len(endpoints) { |
292 case 1: | 289 case 1: |
293 if endpoints[0].RelationRole != RolePeer { | 290 if endpoints[0].RelationRole != RolePeer { |
294 » » » return nil, nil, fmt.Errorf("state: can't add non-peer r
elation with a single service") | 291 » » » return nil, nil, fmt.Errorf("can't add non-peer relation
with a single service") |
295 } | 292 } |
296 case 2: | 293 case 2: |
297 if !endpoints[0].CanRelateTo(&endpoints[1]) { | 294 if !endpoints[0].CanRelateTo(&endpoints[1]) { |
298 » » » return nil, nil, fmt.Errorf("state: can't add relation b
etween %s and %s", endpoints[0], endpoints[1]) | 295 » » » return nil, nil, fmt.Errorf("can't add relation between
%s and %s", endpoints[0], endpoints[1]) |
299 } | 296 } |
300 default: | 297 default: |
301 » » return nil, nil, fmt.Errorf("state: can't add relations between
%d services", len(endpoints)) | 298 » » return nil, nil, fmt.Errorf("can't add relations between %d serv
ices", len(endpoints)) |
302 } | 299 } |
303 t, err := readTopology(s.zk) | 300 t, err := readTopology(s.zk) |
304 if err != nil { | 301 if err != nil { |
305 return nil, nil, err | 302 return nil, nil, err |
306 } | 303 } |
307 // Check if the relation already exists. | 304 // Check if the relation already exists. |
308 relationKey, err := t.RelationKey(endpoints...) | 305 relationKey, err := t.RelationKey(endpoints...) |
309 if err != nil { | 306 if err != nil { |
310 if _, ok := err.(*NoRelationError); !ok { | 307 if _, ok := err.(*NoRelationError); !ok { |
311 return nil, nil, err | 308 return nil, nil, err |
312 } | 309 } |
313 } | 310 } |
314 if relationKey != "" { | 311 if relationKey != "" { |
315 » » return nil, nil, fmt.Errorf("state: relation already exists") | 312 » » return nil, nil, fmt.Errorf("relation already exists") |
316 } | 313 } |
317 scope := ScopeGlobal | 314 scope := ScopeGlobal |
318 for _, endpoint := range endpoints { | 315 for _, endpoint := range endpoints { |
319 if endpoint.RelationScope == ScopeContainer { | 316 if endpoint.RelationScope == ScopeContainer { |
320 scope = ScopeContainer | 317 scope = ScopeContainer |
321 break | 318 break |
322 } | 319 } |
323 } | 320 } |
324 // Add a new relation node depending on the scope. Afterwards | 321 // Add a new relation node depending on the scope. Afterwards |
325 // create a node and a service relation per endpoint. | 322 // create a node and a service relation per endpoint. |
326 relationKey, err = s.addRelationNode(scope) | 323 relationKey, err = s.addRelationNode(scope) |
327 if err != nil { | 324 if err != nil { |
328 return nil, nil, err | 325 return nil, nil, err |
329 } | 326 } |
330 serviceRelations := []*ServiceRelation{} | 327 serviceRelations := []*ServiceRelation{} |
331 for _, endpoint := range endpoints { | 328 for _, endpoint := range endpoints { |
332 serviceKey, err := t.ServiceKey(endpoint.ServiceName) | 329 serviceKey, err := t.ServiceKey(endpoint.ServiceName) |
333 if err != nil { | 330 if err != nil { |
334 return nil, nil, err | 331 return nil, nil, err |
335 } | 332 } |
336 » » err = s.addRelationEndpointNode(relationKey, endpoint, scope) | 333 » » // The relation endpoint node is only created if the scope is· |
337 » » if err != nil { | 334 » » // global. In case of container scoped relations the creation· |
338 » » » return nil, nil, err | 335 » » // per container occurs in ServiceRelation.AddUnit. |
| 336 » » if scope == ScopeGlobal { |
| 337 » » » if err = s.addRelationEndpointNode(relationKey, endpoint
); err != nil { |
| 338 » » » » return nil, nil, err |
| 339 » » » } |
339 } | 340 } |
340 serviceRelations = append(serviceRelations, &ServiceRelation{ | 341 serviceRelations = append(serviceRelations, &ServiceRelation{ |
341 st: s, | 342 st: s, |
342 relationKey: relationKey, | 343 relationKey: relationKey, |
343 serviceKey: serviceKey, | 344 serviceKey: serviceKey, |
344 relationScope: endpoint.RelationScope, | 345 relationScope: endpoint.RelationScope, |
345 relationRole: endpoint.RelationRole, | 346 relationRole: endpoint.RelationRole, |
346 relationName: endpoint.RelationName, | 347 relationName: endpoint.RelationName, |
347 }) | 348 }) |
348 } | 349 } |
349 // Add relation to topology. | 350 // Add relation to topology. |
350 addRelation := func(t *topology) error { | 351 addRelation := func(t *topology) error { |
351 » » relation := &zkRelation{ | 352 » » relation := &topoRelation{ |
352 Interface: endpoints[0].Interface, | 353 Interface: endpoints[0].Interface, |
353 Scope: scope, | 354 Scope: scope, |
354 » » » Services: map[RelationRole]*zkRelationService{}, | 355 » » » Services: map[RelationRole]*topoRelationService{}, |
355 } | 356 } |
356 for _, serviceRelation := range serviceRelations { | 357 for _, serviceRelation := range serviceRelations { |
357 if !t.HasService(serviceRelation.serviceKey) { | 358 if !t.HasService(serviceRelation.serviceKey) { |
358 » » » » return fmt.Errorf("state: state for service %q h
as changed", serviceRelation.serviceKey) | 359 » » » » return fmt.Errorf("state for service %q has chan
ged", serviceRelation.serviceKey) |
359 } | 360 } |
360 » » » service := &zkRelationService{ | 361 » » » service := &topoRelationService{ |
361 Service: serviceRelation.serviceKey, | 362 Service: serviceRelation.serviceKey, |
362 RelationName: serviceRelation.RelationName(), | 363 RelationName: serviceRelation.RelationName(), |
363 } | 364 } |
364 relation.Services[serviceRelation.RelationRole()] = serv
ice | 365 relation.Services[serviceRelation.RelationRole()] = serv
ice |
365 } | 366 } |
366 return t.AddRelation(relationKey, relation) | 367 return t.AddRelation(relationKey, relation) |
367 } | 368 } |
368 err = retryTopologyChange(s.zk, addRelation) | 369 err = retryTopologyChange(s.zk, addRelation) |
369 if err != nil { | 370 if err != nil { |
370 return nil, nil, err | 371 return nil, nil, err |
371 } | 372 } |
372 return &Relation{s, relationKey}, serviceRelations, nil | 373 return &Relation{s, relationKey}, serviceRelations, nil |
373 } | 374 } |
LEFT | RIGHT |