Merge lp:~jimbaker/pyjuju/must-specify-relation-name into lp:pyjuju

Proposed by Jim Baker
Status: Merged
Approved by: Kapil Thangavelu
Approved revision: 516
Merged at revision: 519
Proposed branch: lp:~jimbaker/pyjuju/must-specify-relation-name
Merge into: lp:pyjuju
Diff against target: 188 lines (+72/-11)
4 files modified
juju/hooks/commands.py (+11/-3)
juju/hooks/protocol.py (+16/-2)
juju/hooks/tests/test_communications.py (+16/-2)
juju/hooks/tests/test_invoker.py (+29/-4)
To merge this branch: bzr merge lp:~jimbaker/pyjuju/must-specify-relation-name
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+101156@code.launchpad.net

Description of the change

relation-ids should default to $JUJU_RELATION

If no relation name is specified for the relation-ids hook command, it should default to $JUJU_RELATION. If that's not available, it should raise an error stating "Relation name must be specified".

https://codereview.appspot.com/5991058/

To post a comment you must log in.
Revision history for this message
Jim Baker (jimbaker) wrote :
Download full text (7.9 KiB)

Reviewers: mp+101156_code.launchpad.net,

Message:
Please take a look.

Description:
relation-ids should default to $JUJU_RELATION

If no relation name is specified for the relation-ids hook command, it
should default to $JUJU_RELATION. If that's not available, it should
raise an error stating "Relation name must be specified".

https://code.launchpad.net/~jimbaker/juju/must-specify-relation-name/+merge/101156

(do not edit description out of merge proposal)

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

Affected files:
   A [revision details]
   M juju/hooks/commands.py
   M juju/hooks/protocol.py
   M juju/hooks/tests/test_communications.py
   M juju/hooks/tests/test_invoker.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/hooks/commands.py
=== modified file 'juju/hooks/commands.py'
--- juju/hooks/commands.py 2012-04-05 00:58:19 +0000
+++ juju/hooks/commands.py 2012-04-06 20:29:41 +0000
@@ -98,12 +98,15 @@
      keyvalue_pairs = False

      def customize_parser(self):
+ relation_name = os.environ.get("JUJU_RELATION", "")
+
          self.parser.add_argument(
              "relation_name",
              metavar="RELATION NAME",
              nargs="?",
- default="",
- help="Specify the relation name of the relation ids to list.")
+ default=relation_name,
+ help=("Specify the relation name of the relation ids to list. "
+ "Defaults to $JUJU_RELATION, if available."))

      def run(self):
          return self.client.relation_ids(

Index: juju/hooks/protocol.py
=== modified file 'juju/hooks/protocol.py'
--- juju/hooks/protocol.py 2012-04-05 16:38:15 +0000
+++ juju/hooks/protocol.py 2012-04-06 20:29:41 +0000
@@ -73,11 +73,19 @@
      """

+class MustSpecifyRelationName(JujuError):
+ """No relation name was specified."""
+
+ def __str__(self):
+ return "Relation name must be specified"
+
+
  class BaseCommand(amp.Command):
      errors = {NoSuchUnit: "NoSuchUnit",
                NoSuchKey: "NoSuchKey",
                NotRelationContext: "NotRelationContext",
- UnitRelationStateNotFound: "UnitRelationStateNotFound"}
+ UnitRelationStateNotFound: "UnitRelationStateNotFound",
+ MustSpecifyRelationName: "MustSpecifyRelationName"}

  # All the commands below this point should be documented in the
@@ -243,9 +251,15 @@
      def relation_ids(self, client_id, relation_name):
          """Set values into state.hook.RelationHookContext.

+ :client_id: hooks client id that is used to define a context
+ for a consistent view of state.
+
          :param relation_name: The relation name to query relation ids
- for this context.
+ for this context. If no such relation name is specified,
+ raises `MustSpecifyRelationName`.
          """
+ if not relation_name:
+ raise MustS...

Read more...

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

This is almost a trivial branch.. but.. its a bit odd that this bothers
to do a round trip to the server just to get an error that the client
could trivially check for before every doing the rpc, please add that
check.

https://codereview.appspot.com/5991058/

Revision history for this message
Jim Baker (jimbaker) wrote :
516. By Jim Baker

Client side check

Revision history for this message
Jim Baker (jimbaker) wrote :

I have added this check on the client side.

https://codereview.appspot.com/5991058/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'juju/hooks/commands.py'
2--- juju/hooks/commands.py 2012-04-05 00:58:19 +0000
3+++ juju/hooks/commands.py 2012-04-10 16:45:23 +0000
4@@ -8,6 +8,7 @@
5
6 from juju.hooks.cli import (
7 CommandLineClient, parse_log_level, parse_port_protocol)
8+from juju.hooks.protocol import MustSpecifyRelationName
9
10
11 BAD_CHARS = re.compile("[\-\./:()<>|?*]|(\\\)")
12@@ -98,16 +99,23 @@
13 keyvalue_pairs = False
14
15 def customize_parser(self):
16+ relation_name = os.environ.get("JUJU_RELATION", "")
17+
18 self.parser.add_argument(
19 "relation_name",
20 metavar="RELATION NAME",
21 nargs="?",
22- default="",
23- help="Specify the relation name of the relation ids to list.")
24+ default=relation_name,
25+ help=("Specify the relation name of the relation ids to list. "
26+ "Defaults to $JUJU_RELATION, if available."))
27
28+ @inlineCallbacks
29 def run(self):
30- return self.client.relation_ids(
31+ if not self.options.relation_name:
32+ raise MustSpecifyRelationName()
33+ result = yield self.client.relation_ids(
34 self.options.client_id, self.options.relation_name)
35+ returnValue(result)
36
37
38 def relation_ids():
39
40=== modified file 'juju/hooks/protocol.py'
41--- juju/hooks/protocol.py 2012-04-05 16:38:15 +0000
42+++ juju/hooks/protocol.py 2012-04-10 16:45:23 +0000
43@@ -73,11 +73,19 @@
44 """
45
46
47+class MustSpecifyRelationName(JujuError):
48+ """No relation name was specified."""
49+
50+ def __str__(self):
51+ return "Relation name must be specified"
52+
53+
54 class BaseCommand(amp.Command):
55 errors = {NoSuchUnit: "NoSuchUnit",
56 NoSuchKey: "NoSuchKey",
57 NotRelationContext: "NotRelationContext",
58- UnitRelationStateNotFound: "UnitRelationStateNotFound"}
59+ UnitRelationStateNotFound: "UnitRelationStateNotFound",
60+ MustSpecifyRelationName: "MustSpecifyRelationName"}
61
62
63 # All the commands below this point should be documented in the
64@@ -243,9 +251,15 @@
65 def relation_ids(self, client_id, relation_name):
66 """Set values into state.hook.RelationHookContext.
67
68+ :client_id: hooks client id that is used to define a context
69+ for a consistent view of state.
70+
71 :param relation_name: The relation name to query relation ids
72- for this context.
73+ for this context. If no such relation name is specified,
74+ raises `MustSpecifyRelationName`.
75 """
76+ if not relation_name:
77+ raise MustSpecifyRelationName()
78 context = yield self.factory.get_context(client_id)
79 ids = yield context.get_relation_idents(relation_name)
80 defer.returnValue(dict(ids=" ".join(ids)))
81
82=== modified file 'juju/hooks/tests/test_communications.py'
83--- juju/hooks/tests/test_communications.py 2012-04-05 00:49:40 +0000
84+++ juju/hooks/tests/test_communications.py 2012-04-10 16:45:23 +0000
85@@ -3,10 +3,10 @@
86
87 from twisted.internet import protocol, defer, error
88
89+from juju.errors import JujuError
90 from juju.hooks.protocol import (UnitAgentClient, UnitAgentServer,
91 UnitSettingsFactory, NoSuchUnit,
92- NoSuchKey)
93-
94+ NoSuchKey, MustSpecifyRelationName)
95 from juju.lib.mocker import ANY
96 from juju.lib.testing import TestCase
97 from juju.lib.twistutils import gather_results
98@@ -305,6 +305,14 @@
99 self.assertEquals(self.server.data["test_node"]["a"], "b")
100 self.assertEquals(self.server.data["test_node"]["foo"], "bar")
101
102+ def test_must_specify_relation_name(self):
103+ """Verify `MustSpecifyRelationName` exception`"""
104+ error = MustSpecifyRelationName()
105+ self.assertTrue(isinstance(error, JujuError))
106+ self.assertEquals(
107+ str(error),
108+ "Relation name must be specified")
109+
110 @defer.inlineCallbacks
111 def test_relation_ids(self):
112 """Verify api support of relation_ids command"""
113@@ -318,6 +326,12 @@
114 relation_idents = yield self.client.relation_ids("client_id", "db")
115 self.assertEqual(relation_idents, ["db:0", "db:1", "db:42"])
116
117+ # A relation name must be specified.
118+ e = yield self.assertFailure(
119+ self.client.relation_ids("client_id", ""),
120+ MustSpecifyRelationName)
121+ self.assertEqual(str(e), "Relation name must be specified")
122+
123 @defer.inlineCallbacks
124 def test_list_relations(self):
125 # Allow our testing class to pass the usual guard
126
127=== modified file 'juju/hooks/tests/test_invoker.py'
128--- juju/hooks/tests/test_invoker.py 2012-04-06 11:19:31 +0000
129+++ juju/hooks/tests/test_invoker.py 2012-04-10 16:45:23 +0000
130@@ -1113,7 +1113,7 @@
131 client_id="client_id")
132
133 # Then verify the hook lists the relation ids corresponding to
134- # the relation name `db`; it will not return `db-admin`
135+ # the relation name `db`
136 hook = self.create_hook("relation-ids", "--format=json db")
137 result = yield exe(hook)
138 self.assertEqual(result, 0)
139@@ -1128,13 +1128,18 @@
140 yield self.add_a_blog("wordpress2")
141 yield self.add_db_admin_tool("admin")
142
143- # Invoker will be in the context of the mysql/0 service unit
144+ # Invoker will be in the context of the mysql/0 service
145+ # unit. This test file's mock unit agent does not set the
146+ # additional environment variables for relation hooks that are
147+ # set by juju.unit.lifecycle.RelationInvoker; instead it has
148+ # to be set by individual tests.
149 exe = yield self.ua.get_invoker(
150 "db:0", "add", "mysql/0", self.relation,
151 client_id="client_id")
152+ exe.environment["JUJU_RELATION"] = "db"
153
154 # Then verify the hook lists the relation ids corresponding to
155- # any relation name
156+ # to JUJU_RELATION (="db")
157 hook_log = self.capture_logging("hook")
158 hook = self.create_hook("relation-ids", "--format=json")
159 result = yield exe(hook)
160@@ -1142,7 +1147,27 @@
161 yield exe.ended
162 self.assertEqual(
163 set(json.loads(hook_log.getvalue())),
164- set(["db:0", "db:1", "db-admin:2"]))
165+ set(["db:0", "db:1"]))
166+
167+ # This time pretend this is a nonrelational hook
168+ # context. Ignore the relation stuff in the get_invoker
169+ # function below, really it is a nonrelational hook as far as
170+ # the hook commands are concerned:
171+ exe = yield self.ua.get_invoker(
172+ "db:0", "add", "mysql/0", self.relation,
173+ client_id="client_id")
174+ hook_log = self.capture_logging("hook")
175+ hook = self.create_hook("relation-ids", "--format=json")
176+ result = yield exe(hook)
177+
178+ # Currently, exceptions of all hook commands are only logged;
179+ # the exit code is always set to 0.
180+ self.assertEqual(result, 0)
181+ yield exe.ended
182+ self.assertIn(
183+ ("juju.hooks.protocol.MustSpecifyRelationName: "
184+ "Relation name must be specified"),
185+ hook_log.getvalue())
186
187 @defer.inlineCallbacks
188 def test_relation_set_with_relation_id_option(self):

Subscribers

People subscribed via source and target branches

to status/vote changes: