Merge lp:~niedbalski/python-jujuclient/lp-1456332 into lp:python-jujuclient

Proposed by Jorge Niedbalski
Status: Superseded
Proposed branch: lp:~niedbalski/python-jujuclient/lp-1456332
Merge into: lp:python-jujuclient
Diff against target: 138 lines (+95/-5)
2 files modified
jujuclient.py (+31/-5)
test_jujuclient.py (+64/-0)
To merge this branch: bzr merge lp:~niedbalski/python-jujuclient/lp-1456332
Reviewer Review Type Date Requested Status
Tim Van Steenburgh Pending
Felipe Reyes Pending
Review via email: mp+259449@code.launchpad.net

This proposal supersedes a proposal from 2015-05-18.

This proposal has been superseded by a proposal from 2015-05-19.

Description of the change

This patch fixes LP: #1456332

To post a comment you must log in.
Revision history for this message
Tim Van Steenburgh (tvansteenburgh) wrote : Posted in a previous version of this proposal

One minor quibble: it's not clear what happens if you call Run without providing any machines, services, or units. Is that an error from Juju, or is it the equivalent of calling RunOnAllMachines? It would be great to clarify this in the run() docstring.

Otherwise looks good, pending a successful test run.

review: Needs Fixing
Revision history for this message
Felipe Reyes (freyes) wrote : Posted in a previous version of this proposal

Hi @niedbalski, I was reviewing your patch and looks fine to me, but I would like to ask you to add two more tests, to test when units are passed and another one for service, at the moment you're only testing with machines.

Best,

review: Needs Fixing
Revision history for this message
Jorge Niedbalski (niedbalski) wrote : Posted in a previous version of this proposal

Thanks guys for taking the time for reviewing.

@Tim,

I think that this is indeed a Juju-core validation error.

I submitted a PR for handling this on the server side: https://github.com/juju/juju/pull/2355

I don't think we should threat this as a special case, since this is a library and
the RPC call should warn about that. But, if you have any other idea, please let me know.

@Felipe,

I re-submitted addressing your comments adding 2 new tests.

Revision history for this message
Jorge Niedbalski (niedbalski) wrote : Posted in a previous version of this proposal

@Tim

I added an assertion if no target is passed, just in case.

60. By Jorge Niedbalski

assert if no target is passed

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'jujuclient.py'
2--- jujuclient.py 2015-05-11 14:33:56 +0000
3+++ jujuclient.py 2015-05-19 01:17:38 +0000
4@@ -273,7 +273,7 @@
5 def _rpc(self, op):
6 if not self._auth and not op.get("Request") == "Login":
7 raise LoginRequired()
8- if not 'Params' in op:
9+ if 'Params' not in op:
10 op['Params'] = {}
11 op['RequestId'] = self._request_id
12 self._request_id += 1
13@@ -813,14 +813,40 @@
14 "Params": {"Commands": command,
15 "Timeout": timeout}})
16
17- def run(self, targets, command, timeout=None):
18+ def run(self, command, timeout=None, machines=None,
19+ services=None, units=None):
20 """Run a shell command on the targets (services, units, or machines).
21+ At least one target must be specified machines || services || units
22 """
23- return self._rpc({
24+
25+ assert not (not machines and not services and not units), \
26+ "You must specify a target"
27+
28+ rpc_dict = {
29 "Type": "Client",
30 "Request": "Run",
31- "Params": {"Commands": command,
32- "Timeout": timeout}})
33+ "Params": {
34+ "Commands": command,
35+ "Timeout": timeout,
36+ }
37+ }
38+
39+ if machines:
40+ if not isinstance(machines, (list, tuple)):
41+ machines = [machines]
42+ rpc_dict.update({'Machines': machines})
43+
44+ if services:
45+ if not isinstance(services, (list, tuple)):
46+ services = [services]
47+ rpc_dict.update({'Services': services})
48+
49+ if units:
50+ if not isinstance(units, (list, tuple)):
51+ units = [units]
52+ rpc_dict.update({'Units': units})
53+
54+ return self._rpc(rpc_dict)
55
56 # Machine ops
57 def add_machine(self, series="", constraints=None,
58
59=== modified file 'test_jujuclient.py'
60--- test_jujuclient.py 2015-05-11 14:33:56 +0000
61+++ test_jujuclient.py 2015-05-19 01:17:38 +0000
62@@ -83,6 +83,7 @@
63 ValueError, Connector.split_host_port, 'I am not an ip/port combo'
64 )
65
66+
67 class KeyManagerTest(unittest.TestCase):
68 def setUp(self):
69 self.env = Environment.connect(ENV_NAME)
70@@ -382,5 +383,68 @@
71 pass
72
73
74+class TestEnvironment(unittest.TestCase):
75+
76+ def setUp(self):
77+ self.env = Environment.connect(ENV_NAME)
78+
79+ def test_run_no_target(self):
80+ self.assertRaises(AssertionError, self.env.run, "sudo test")
81+
82+ def test_run_target_machines(self):
83+ with mock.patch.object(self.env, '_rpc',
84+ return_value=None) as rpc:
85+ self.env.run("sudo test", machines=["0", "1"])
86+
87+ rpc.assert_called_once_with({
88+ "Type": "Client",
89+ "Request": "Run",
90+ "Params": {
91+ "Commands": "sudo test",
92+ "Timeout": None,
93+ },
94+ "Machines": [
95+ '0',
96+ '1',
97+ ]
98+ })
99+
100+ def test_run_target_services(self):
101+ with mock.patch.object(self.env, '_rpc',
102+ return_value=None) as rpc:
103+ self.env.run("sudo test", services=["cinder", "glance"])
104+
105+ rpc.assert_called_once_with({
106+ "Type": "Client",
107+ "Request": "Run",
108+ "Params": {
109+ "Commands": "sudo test",
110+ "Timeout": None,
111+ },
112+ "Services": [
113+ 'cinder',
114+ 'glance',
115+ ]
116+ })
117+
118+ def test_run_target_units(self):
119+ with mock.patch.object(self.env, '_rpc',
120+ return_value=None) as rpc:
121+ self.env.run("sudo test", units=["mysql/0", "mysql/1"])
122+
123+ rpc.assert_called_once_with({
124+ "Type": "Client",
125+ "Request": "Run",
126+ "Params": {
127+ "Commands": "sudo test",
128+ "Timeout": None,
129+ },
130+ "Units": [
131+ 'mysql/0',
132+ 'mysql/1',
133+ ]
134+ })
135+
136+
137 if __name__ == '__main__':
138 unittest.main()

Subscribers

People subscribed via source and target branches