Merge lp:~hazmat/pyjuju/peers-from-hurd into lp:pyjuju

Proposed by Kapil Thangavelu
Status: Merged
Merged at revision: 615
Proposed branch: lp:~hazmat/pyjuju/peers-from-hurd
Merge into: lp:pyjuju
Diff against target: 138 lines (+60/-12)
3 files modified
juju/control/remove_relation.py (+1/-1)
juju/unit/lifecycle.py (+39/-5)
juju/unit/tests/test_lifecycle.py (+20/-6)
To merge this branch: bzr merge lp:~hazmat/pyjuju/peers-from-hurd
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+148528@code.launchpad.net

Description of the change

Unit process multiple relations in defined order.

Previously when unit agents were being notified of multiple relations, typicaly
at startup, they would process them in essentially random order. This would
complicate things for applications that would have peer relations as well, for
ha or replication, as they couldn't tell if they were being run standalone or
in a cluster/quorum. Instead when a unit has multiple relations, we process
peer relations first followed by client/server relations.

https://codereview.appspot.com/7341044/

To post a comment you must log in.
Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Download full text (6.3 KiB)

Reviewers: mp+148528_code.launchpad.net,

Message:
Please take a look.

Description:
Unit process multiple relations in defined order.

Previously when unit agents were being notified of multiple relations,
typicaly
at startup, they would process them in essentially random order. This
would
complicate things for applications that would have peer relations as
well, for
ha or replication, as they couldn't tell if they were being run
standalone or
in a cluster/quorum. Instead when a unit has multiple relations, we
process
the relations in creation order, given that a service's peer relations
are
always created upon service deploy, this gives deterministic behavior
that
solves the use case instead of previous random order.

https://code.launchpad.net/~hazmat/juju/peers-from-hurd/+merge/148528

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/7341044/

Affected files:
   A [revision details]
   M juju/unit/lifecycle.py
   M juju/unit/tests/test_lifecycle.py

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>

Index: juju/unit/lifecycle.py
=== modified file 'juju/unit/lifecycle.py'
--- juju/unit/lifecycle.py 2012-09-10 03:20:20 +0000
+++ juju/unit/lifecycle.py 2013-02-14 18:29:42 +0000
@@ -374,8 +374,15 @@
                  (service_relation.internal_relation_id, service_relation)
                  for service_relation in old_relations)

- added = set(new_relations.keys()) - set(self._relations.keys())
- removed = set(self._relations.keys()) - set(new_relations.keys())
+ # We process new relations in creation order, and remove rels
+ # most recently created to oldest. As a consequence, this
+ # ensures that new peer relations are processed (created at
+ # service deployment) are processed before client/server
+ # relations when multiple rels are available at unit startup.
+ added = sorted(set(new_relations.keys()) -
set(self._relations.keys()))
+ removed = list(reversed(sorted(
+ set(self._relations.keys()) - set(new_relations.keys()))))
+
          # Could this service be a principal container?
          is_principal = not (yield self._service.is_subordinate())

@@ -404,12 +411,13 @@
                  yield workflow.transition_state("departed")
              self._store_relations()

- # Process new relations.
+ # Process new relations
          for relation_id in added:
              service_relation = new_relations[relation_id]
              yield self._add_relation(service_relation)
- if (is_principal and service_relation.relation_scope
== "container"):
- self._add_subordinate_unit(service_relation)
+ if (is_principal
+ and service_relation.relation_scope == "container"):
+ yield self._add_subordinate_unit(service_relation)
              yield self._store_relations()

      @i...

Read more...

Revision history for this message
Benjamin Saller (bcsaller) wrote :

LGTM so long as contract is documented as we talked about on the call.
Thanks.

https://codereview.appspot.com/7341044/

lp:~hazmat/pyjuju/peers-from-hurd updated
618. By Kapil Thangavelu

clean up comments

619. By Kapil Thangavelu

redo rel sorting, as peers rels can be recreated

Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Revision history for this message
Kapil Thangavelu (hazmat) wrote :

On 2013/02/14 23:01:19, hazmat wrote:
> Please take a look.

this time more explicit about peer behavior with a custom sort function
and explicit test of peers instead of pure creation order.

https://codereview.appspot.com/7341044/

Revision history for this message
Benjamin Saller (bcsaller) wrote :

That is better, thanks for following up on that. +1

https://codereview.appspot.com/7341044/

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

*** Submitted:

Unit process multiple relations in defined order.

Previously when unit agents were being notified of multiple relations,
typicaly
at startup, they would process them in essentially random order. This
would
complicate things for applications that would have peer relations as
well, for
ha or replication, as they couldn't tell if they were being run
standalone or
in a cluster/quorum. Instead when a unit has multiple relations, we
process
peer relations first followed by client/server relations.

R=bcsaller
CC=
https://codereview.appspot.com/7341044

https://codereview.appspot.com/7341044/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'juju/control/remove_relation.py'
--- juju/control/remove_relation.py 2012-04-12 09:23:50 +0000
+++ juju/control/remove_relation.py 2013-02-14 23:02:23 +0000
@@ -89,4 +89,4 @@
89 yield client.close()89 yield client.close()
9090
91 log.info("Removed %s relation from all service units.",91 log.info("Removed %s relation from all service units.",
92 endpoints[0].relation_type)92 endpoints[0].relation_type)
9393
=== modified file 'juju/unit/lifecycle.py'
--- juju/unit/lifecycle.py 2012-09-10 03:20:20 +0000
+++ juju/unit/lifecycle.py 2013-02-14 23:02:23 +0000
@@ -360,6 +360,30 @@
360 finally:360 finally:
361 self._run_lock.release()361 self._run_lock.release()
362362
363 def _sort_relations(self, rel_ids, rels, invert=False):
364 """ Sort a set of relations.
365
366 We process peer relations first when adding, and last when
367 removing, else deferring to creation order.
368 """
369 rel_ids = list(rel_ids)
370
371 def _sort(x, y):
372 xr, yr = rels[x].relation_role, rels[y].relation_role
373 if xr == yr:
374 return cmp(x, y)
375 elif xr == "peer":
376 return -1
377 elif yr == "peer":
378 return 1
379 return cmp(x, y)
380
381 rel_ids.sort(_sort)
382
383 if invert:
384 return list(reversed(rel_ids))
385 return rel_ids
386
363 @inlineCallbacks387 @inlineCallbacks
364 def _process_service_changes(self, old_relations, new_relations):388 def _process_service_changes(self, old_relations, new_relations):
365 """Add and remove unit lifecycles per the service relations Determine.389 """Add and remove unit lifecycles per the service relations Determine.
@@ -374,8 +398,17 @@
374 (service_relation.internal_relation_id, service_relation)398 (service_relation.internal_relation_id, service_relation)
375 for service_relation in old_relations)399 for service_relation in old_relations)
376400
377 added = set(new_relations.keys()) - set(self._relations.keys())401 added = self._sort_relations(
378 removed = set(self._relations.keys()) - set(new_relations.keys())402 set(new_relations.keys()) - set(self._relations.keys()),
403 new_relations)
404 print 'add', added, [new_relations[a] for a in added]
405
406 removed = self._sort_relations(
407 set(self._relations.keys()) - set(new_relations.keys()),
408 self._relations,
409 invert=True)
410 print 'removed', removed
411
379 # Could this service be a principal container?412 # Could this service be a principal container?
380 is_principal = not (yield self._service.is_subordinate())413 is_principal = not (yield self._service.is_subordinate())
381414
@@ -404,12 +437,13 @@
404 yield workflow.transition_state("departed")437 yield workflow.transition_state("departed")
405 self._store_relations()438 self._store_relations()
406439
407 # Process new relations.440 # Process new relations
408 for relation_id in added:441 for relation_id in added:
409 service_relation = new_relations[relation_id]442 service_relation = new_relations[relation_id]
410 yield self._add_relation(service_relation)443 yield self._add_relation(service_relation)
411 if (is_principal and service_relation.relation_scope == "container"):444 if (is_principal
412 self._add_subordinate_unit(service_relation)445 and service_relation.relation_scope == "container"):
446 yield self._add_subordinate_unit(service_relation)
413 yield self._store_relations()447 yield self._store_relations()
414448
415 @inlineCallbacks449 @inlineCallbacks
416450
=== modified file 'juju/unit/tests/test_lifecycle.py'
--- juju/unit/tests/test_lifecycle.py 2013-02-01 16:24:08 +0000
+++ juju/unit/tests/test_lifecycle.py 2013-02-14 23:02:23 +0000
@@ -34,7 +34,7 @@
34from juju.unit.tests.test_charm import CharmPublisherTestBase34from juju.unit.tests.test_charm import CharmPublisherTestBase
3535
36from juju.lib.testing import TestCase36from juju.lib.testing import TestCase
37from juju.lib.mocker import MATCH37from juju.lib.mocker import MATCH, ANY
3838
3939
40class UnwriteablePath(object):40class UnwriteablePath(object):
@@ -893,6 +893,20 @@
893 self.assertEqual("up", (yield staying_workflow.get_state()))893 self.assertEqual("up", (yield staying_workflow.get_state()))
894 yield new_lifecycle.stop()894 yield new_lifecycle.stop()
895895
896 def test_multiple_rel_order(self):
897 """Given multiple new rels, verify peer processed first."""
898
899 class rel(object):
900 def __init__(self, r):
901 self.relation_role = r
902
903 rels = {'5': rel('peer'), '4': rel('client'),
904 '2': rel('server'), '1': rel('peer')}
905
906 self.assertEqual(
907 self.lifecycle._sort_relations(rels.keys(), rels),
908 ["1", "5", "2", "4"])
909
896 @inlineCallbacks910 @inlineCallbacks
897 def test_start_invoker(self):911 def test_start_invoker(self):
898 """Verify the invoker is started by the unit relation lifecycle"""912 """Verify the invoker is started by the unit relation lifecycle"""
@@ -901,7 +915,7 @@
901 # these will be on the relation with ident app:0, app:1, app:2915 # these will be on the relation with ident app:0, app:1, app:2
902 self.write_hook(916 self.write_hook(
903 "start",917 "start",
904 '#!/bin/sh\n echo "hello world"\n')918 '#!/bin/sh\n echo hello\n')
905 blog_states = yield self.add_opposite_service_unit(self.states)919 blog_states = yield self.add_opposite_service_unit(self.states)
906 yield blog_states['service_relations'][-1].add_unit_state(920 yield blog_states['service_relations'][-1].add_unit_state(
907 self.states['unit'])921 self.states['unit'])
@@ -909,10 +923,10 @@
909 for i in range(1, 3):923 for i in range(1, 3):
910 blog_states = yield self.add_opposite_service_unit(924 blog_states = yield self.add_opposite_service_unit(
911 (yield self.add_relation_service_unit_to_another_endpoint(925 (yield self.add_relation_service_unit_to_another_endpoint(
912 self.states,926 self.states,
913 RelationEndpoint(927 RelationEndpoint(
914 "wordpress-%d" % i,928 "wordpress-%d" % i,
915 "client-server", "db", "client"))))929 "client-server", "db", "client"))))
916 yield blog_states['service_relations'][-1].add_unit_state(930 yield blog_states['service_relations'][-1].add_unit_state(
917 self.states['unit'])931 self.states['unit'])
918932

Subscribers

People subscribed via source and target branches

to status/vote changes: