LEFT | RIGHT |
1 package state | 1 package state |
2 | 2 |
3 import ( | 3 import ( |
4 "errors" | 4 "errors" |
5 "fmt" | 5 "fmt" |
6 "launchpad.net/goyaml" | 6 "launchpad.net/goyaml" |
7 "launchpad.net/gozk/zookeeper" | 7 "launchpad.net/gozk/zookeeper" |
8 "sort" | 8 "sort" |
9 ) | 9 ) |
10 | 10 |
11 // The protocol version, which is stored in the /topology node under | 11 // The protocol version, which is stored in the /topology node under |
12 // the "version" key. The protocol version should *only* be updated | 12 // the "version" key. The protocol version should *only* be updated |
13 // when we know that a version is in fact actually incompatible. | 13 // when we know that a version is in fact actually incompatible. |
14 const topologyVersion = 1 | 14 const topologyVersion = 1 |
15 | 15 |
16 // NoRelationError represents a relation not found for one or more endpoints. | 16 // NoRelationError represents a relation not found for one or more endpoints. |
17 type NoRelationError struct { | 17 type NoRelationError struct { |
18 Endpoints []RelationEndpoint | 18 Endpoints []RelationEndpoint |
19 } | 19 } |
20 | 20 |
21 // Error returns the string representation of the error. | 21 // Error returns the string representation of the error. |
22 func (e NoRelationError) Error() string { | 22 func (e NoRelationError) Error() string { |
23 switch len(e.Endpoints) { | 23 switch len(e.Endpoints) { |
24 case 1: | 24 case 1: |
25 » » return fmt.Sprintf("state: no peer relation for %q", e.Endpoints
[0].Id()) | 25 » » return fmt.Sprintf("state: no peer relation for %q", e.Endpoints
[0]) |
26 case 2: | 26 case 2: |
27 » » return fmt.Sprintf("state: no relation between %q and %q", e.End
points[0].Id(), e.Endpoints[1].Id()) | 27 » » return fmt.Sprintf("state: no relation between %q and %q", e.End
points[0], e.Endpoints[1]) |
28 » } | 28 » } |
29 » panic("state: illegal relation error") | 29 » panic("state: illegal relation") |
30 } | 30 } |
31 | 31 |
32 // zkTopology is used to marshal and unmarshal the content | 32 // zkTopology is used to marshal and unmarshal the content |
33 // of the /topology node in ZooKeeper. | 33 // of the /topology node in ZooKeeper. |
34 type zkTopology struct { | 34 type zkTopology struct { |
35 Version int | 35 Version int |
36 Machines map[string]*zkMachine | 36 Machines map[string]*zkMachine |
37 Services map[string]*zkService | 37 Services map[string]*zkService |
38 UnitSequence map[string]int "unit-sequence" | 38 UnitSequence map[string]int "unit-sequence" |
39 Relations map[string]*zkRelation | 39 Relations map[string]*zkRelation |
(...skipping 16 matching lines...) Expand all Loading... |
56 type zkUnit struct { | 56 type zkUnit struct { |
57 Sequence int | 57 Sequence int |
58 Machine string | 58 Machine string |
59 } | 59 } |
60 | 60 |
61 // zkRelation represents the relation data within the· | 61 // zkRelation represents the relation data within the· |
62 // /topology node in ZooKeeper. | 62 // /topology node in ZooKeeper. |
63 type zkRelation struct { | 63 type zkRelation struct { |
64 Interface string | 64 Interface string |
65 Scope RelationScope | 65 Scope RelationScope |
66 » Services map[RelationRole]string | 66 » Services map[RelationRole]*zkRelationService |
| 67 } |
| 68 |
| 69 // zkRelationService represents the data of one |
| 70 // service of a relation within the /topology |
| 71 // node in ZooKeeper. |
| 72 type zkRelationService struct { |
| 73 » Service string |
| 74 » RelationName string "relation-name" |
67 } | 75 } |
68 | 76 |
69 // check verifies that r is a proper relation. | 77 // check verifies that r is a proper relation. |
70 func (r *zkRelation) check() error { | 78 func (r *zkRelation) check() error { |
71 if len(r.Interface) == 0 { | 79 if len(r.Interface) == 0 { |
72 return fmt.Errorf("relation interface is empty") | 80 return fmt.Errorf("relation interface is empty") |
73 } | 81 } |
74 if len(r.Services) == 0 { | 82 if len(r.Services) == 0 { |
75 return fmt.Errorf("relation has no services") | 83 return fmt.Errorf("relation has no services") |
76 } | 84 } |
77 counterpart := map[RelationRole]RelationRole{ | 85 counterpart := map[RelationRole]RelationRole{ |
78 RoleRequirer: RoleProvider, | 86 RoleRequirer: RoleProvider, |
79 RoleProvider: RoleRequirer, | 87 RoleProvider: RoleRequirer, |
80 RolePeer: RolePeer, | 88 RolePeer: RolePeer, |
81 } | 89 } |
82 » for serviceRole, serviceKey := range r.Services { | 90 » for serviceRole, service := range r.Services { |
83 » » if serviceKey == "" { | 91 » » if service.Service == "" { |
84 » » » return fmt.Errorf("relation has %s service with empty ke
y", serviceRole) | 92 » » » return fmt.Errorf("relation has %s service with empty se
rvice key", serviceRole) |
| 93 » » } |
| 94 » » if service.RelationName == "" { |
| 95 » » » return fmt.Errorf("relation has %s service with empty re
lation name", serviceRole) |
85 } | 96 } |
86 counterRole, ok := counterpart[serviceRole] | 97 counterRole, ok := counterpart[serviceRole] |
87 if !ok { | 98 if !ok { |
88 return fmt.Errorf("relation has unknown service role: %q
", serviceRole) | 99 return fmt.Errorf("relation has unknown service role: %q
", serviceRole) |
89 } | 100 } |
90 if _, ok := r.Services[counterRole]; !ok { | 101 if _, ok := r.Services[counterRole]; !ok { |
91 return fmt.Errorf("relation has %s but no %s", serviceRo
le, counterRole) | 102 return fmt.Errorf("relation has %s but no %s", serviceRo
le, counterRole) |
92 } | 103 } |
93 } | 104 } |
94 if len(r.Services) > 2 { | 105 if len(r.Services) > 2 { |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 t.topology.Relations = make(map[string]*zkRelation) | 411 t.topology.Relations = make(map[string]*zkRelation) |
401 } | 412 } |
402 _, ok := t.topology.Relations[relationKey] | 413 _, ok := t.topology.Relations[relationKey] |
403 if ok { | 414 if ok { |
404 return fmt.Errorf("relation key %q already in use", relationKey) | 415 return fmt.Errorf("relation key %q already in use", relationKey) |
405 } | 416 } |
406 // Check if the relation definition and the service keys are valid. | 417 // Check if the relation definition and the service keys are valid. |
407 if err := relation.check(); err != nil { | 418 if err := relation.check(); err != nil { |
408 return err | 419 return err |
409 } | 420 } |
410 » for _, serviceKey := range relation.Services { | 421 » for _, service := range relation.Services { |
411 » » if err := t.assertService(serviceKey); err != nil { | 422 » » if err := t.assertService(service.Service); err != nil { |
412 return err | 423 return err |
413 } | 424 } |
414 } | 425 } |
415 » if relation.Services[RolePeer] == "" { | 426 » if relation.Services[RolePeer] == nil { |
416 » » providerKey := relation.Services[RoleProvider] | 427 » » providerKey := relation.Services[RoleProvider].Service |
417 » » requirerKey := relation.Services[RoleRequirer] | 428 » » requirerKey := relation.Services[RoleRequirer].Service |
418 if providerKey == requirerKey { | 429 if providerKey == requirerKey { |
419 » » » return fmt.Errorf("provider and consumer keys must not b
e the same") | 430 » » » return fmt.Errorf("provider and requirer keys must not b
e the same") |
420 } | 431 } |
421 } | 432 } |
422 t.topology.Relations[relationKey] = relation | 433 t.topology.Relations[relationKey] = relation |
423 return nil | 434 return nil |
424 } | 435 } |
425 | 436 |
426 // RelationKeys returns the keys for all relations in the topology. | 437 // RelationKeys returns the keys for all relations in the topology. |
427 func (t *topology) RelationKeys() []string { | 438 func (t *topology) RelationKeys() []string { |
428 keys := []string{} | 439 keys := []string{} |
429 for key, _ := range t.topology.Relations { | 440 for key, _ := range t.topology.Relations { |
430 keys = append(keys, key) | 441 keys = append(keys, key) |
431 } | 442 } |
432 sort.Strings(keys) | 443 sort.Strings(keys) |
433 return keys | 444 return keys |
434 } | 445 } |
435 | 446 |
436 // RemoveRelation removes the relation with key from the topology. | 447 // RemoveRelation removes the relation with key from the topology. |
437 func (t *topology) RemoveRelation(key string) { | 448 func (t *topology) RemoveRelation(key string) { |
438 delete(t.topology.Relations, key) | 449 delete(t.topology.Relations, key) |
439 } | 450 } |
440 | 451 |
441 // RelationsForService returns all relations that the service | 452 // RelationsForService returns all relations that the service |
442 // with serviceKey is part of. | 453 // with serviceKey is part of. |
443 func (t *topology) RelationsForService(serviceKey string) (map[string]*zkRelatio
n, error) { | 454 func (t *topology) RelationsForService(serviceKey string) (map[string]*zkRelatio
n, error) { |
444 if err := t.assertService(serviceKey); err != nil { | 455 if err := t.assertService(serviceKey); err != nil { |
445 return nil, err | 456 return nil, err |
446 } | 457 } |
447 relations := make(map[string]*zkRelation) | 458 relations := make(map[string]*zkRelation) |
448 for relationKey, relation := range t.topology.Relations { | 459 for relationKey, relation := range t.topology.Relations { |
449 » » for _, roleServiceKey := range relation.Services { | 460 » » for _, service := range relation.Services { |
450 » » » if roleServiceKey == serviceKey { | 461 » » » if service.Service == serviceKey { |
451 relations[relationKey] = relation | 462 relations[relationKey] = relation |
452 break | 463 break |
453 } | 464 } |
454 } | 465 } |
455 } | 466 } |
456 return relations, nil | 467 return relations, nil |
457 } | 468 } |
458 | 469 |
459 // RelationKey returns the key for the relation established between the | 470 // RelationKey returns the key for the relation established between the |
460 // provided endpoints. If no matching relation is found, error will be | 471 // provided endpoints. If no matching relation is found, error will be |
461 // of type *NoRelationError. | 472 // of type *NoRelationError. |
462 func (t *topology) RelationKey(endpoints ...RelationEndpoint) (string, error) { | 473 func (t *topology) RelationKey(endpoints ...RelationEndpoint) (string, error) { |
463 if t.topology.Relations == nil { | |
464 return "", &NoRelationError{endpoints} | |
465 } | |
466 switch len(endpoints) { | 474 switch len(endpoints) { |
467 case 1: | 475 case 1: |
468 // Just pass. | 476 // Just pass. |
469 case 2: | 477 case 2: |
470 if endpoints[0].Interface != endpoints[1].Interface { | 478 if endpoints[0].Interface != endpoints[1].Interface { |
471 » » » return "", fmt.Errorf("state: differing interfaces %q an
d %q", endpoints[0].Interface, endpoints[1].Interface) | 479 » » » return "", &NoRelationError{endpoints} |
472 } | 480 } |
473 default: | 481 default: |
474 » » return "", fmt.Errorf("state: illegal number of endpoints passed
") | 482 » » return "", fmt.Errorf("state: illegal number of relation endpoin
ts provided") |
475 } | 483 } |
476 for relationKey, relation := range t.topology.Relations { | 484 for relationKey, relation := range t.topology.Relations { |
477 if relation.Interface != endpoints[0].Interface { | 485 if relation.Interface != endpoints[0].Interface { |
478 continue | 486 continue |
479 } | 487 } |
480 found := true | 488 found := true |
481 for _, endpoint := range endpoints { | 489 for _, endpoint := range endpoints { |
482 » » » serviceKey, ok := relation.Services[endpoint.RelationRol
e] | 490 » » » service, ok := relation.Services[endpoint.RelationRole] |
483 » » » if !ok { | 491 » » » if !ok || service.RelationName != endpoint.RelationName
{ |
484 » » » » found = false | |
485 » » » » break | |
486 » » » } | |
487 » » » serviceName, err := t.ServiceName(serviceKey) | |
488 » » » if err != nil { | |
489 » » » » return "", err | |
490 » » » } | |
491 » » » if serviceName != endpoint.RelationName { | |
492 found = false | 492 found = false |
493 break | 493 break |
494 } | 494 } |
495 } | 495 } |
496 if found { | 496 if found { |
497 // All endpoints tested positive. | 497 // All endpoints tested positive. |
498 return relationKey, nil | 498 return relationKey, nil |
499 } | 499 } |
500 } | 500 } |
501 return "", &NoRelationError{endpoints} | 501 return "", &NoRelationError{endpoints} |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 } | 566 } |
567 } | 567 } |
568 // Apply the passed function. | 568 // Apply the passed function. |
569 if err = f(it); err != nil { | 569 if err = f(it); err != nil { |
570 return "", err | 570 return "", err |
571 } | 571 } |
572 return it.dump() | 572 return it.dump() |
573 } | 573 } |
574 return zk.RetryChange(zkTopologyPath, 0, zkPermAll, change) | 574 return zk.RetryChange(zkTopologyPath, 0, zkPermAll, change) |
575 } | 575 } |
LEFT | RIGHT |