Merge lp:~rvb/maas/stop-button into lp:~maas-committers/maas/trunk

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 1489
Proposed branch: lp:~rvb/maas/stop-button
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 113 lines (+51/-0)
2 files modified
src/maasserver/node_action.py (+15/-0)
src/maasserver/tests/test_node_action.py (+36/-0)
To merge this branch: bzr merge lp:~rvb/maas/stop-button
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) Approve
Review via email: mp+165054@code.launchpad.net

Commit message

Add stop node button.

Description of the change

Add a "stop node" button in the UI.

Drive-by fix: refactored the tests so that each button has it's own test class. It makes it more simple to spot how many tests we have for each type of button and copy the tests over when one creates a new button (and the tests that goes with it).

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Good stuff. Only one very mild suggestion: it would be more specific to tell the user that the node has been asked to "shut down," rather than to "stop."

That makes it more obvious that this is a "stop" at the system level, not at the service level. I'm guessing that it might be slightly puzzling if the request "stop this node" translates to "ask the node to stop" plus something else.

Jeroen

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

> Good stuff. Only one very mild suggestion: it would be more specific to tell
> the user that the node has been asked to "shut down," rather than to "stop."
>
> That makes it more obvious that this is a "stop" at the system level, not at
> the service level. I'm guessing that it might be slightly puzzling if the
> request "stop this node" translates to "ask the node to stop" plus something
> else.

good point, done.

Thanks for the review!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/node_action.py'
--- src/maasserver/node_action.py 2012-05-08 16:22:48 +0000
+++ src/maasserver/node_action.py 2013-05-22 15:31:25 +0000
@@ -196,11 +196,26 @@
196 """)196 """)
197197
198198
199class StopNode(NodeAction):
200 """Stop and release a node."""
201 display = "Stop node"
202 actionable_statuses = (NODE_STATUS.ALLOCATED, )
203 permission = NODE_PERMISSION.EDIT
204
205 def execute(self):
206 self.node.release()
207 return dedent("""\
208 This node is no longer allocated to you.
209 It has been asked to shut down.
210 """)
211
212
199ACTION_CLASSES = (213ACTION_CLASSES = (
200 Delete,214 Delete,
201 AcceptAndCommission,215 AcceptAndCommission,
202 RetryCommissioning,216 RetryCommissioning,
203 StartNode,217 StartNode,
218 StopNode,
204 )219 )
205220
206221
207222
=== modified file 'src/maasserver/tests/test_node_action.py'
--- src/maasserver/tests/test_node_action.py 2012-06-07 11:44:14 +0000
+++ src/maasserver/tests/test_node_action.py 2013-05-22 15:31:25 +0000
@@ -28,10 +28,12 @@
28 NodeAction,28 NodeAction,
29 RetryCommissioning,29 RetryCommissioning,
30 StartNode,30 StartNode,
31 StopNode,
31 )32 )
32from maasserver.testing.factory import factory33from maasserver.testing.factory import factory
33from maasserver.testing.testcase import TestCase34from maasserver.testing.testcase import TestCase
34from provisioningserver.enum import POWER_TYPE35from provisioningserver.enum import POWER_TYPE
36from provisioningserver.power.poweraction import PowerAction
3537
3638
37ALL_STATUSES = NODE_STATUS_CHOICES_DICT.keys()39ALL_STATUSES = NODE_STATUS_CHOICES_DICT.keys()
@@ -162,6 +164,9 @@
162 action.fake_inhibition = factory.getRandomString()164 action.fake_inhibition = factory.getRandomString()
163 self.assertIsNone(action.inhibition)165 self.assertIsNone(action.inhibition)
164166
167
168class TestDeleteNodeAction(TestCase):
169
165 def test_Delete_inhibit_when_node_is_allocated(self):170 def test_Delete_inhibit_when_node_is_allocated(self):
166 node = factory.make_node(status=NODE_STATUS.ALLOCATED)171 node = factory.make_node(status=NODE_STATUS.ALLOCATED)
167 action = Delete(node, factory.make_admin())172 action = Delete(node, factory.make_admin())
@@ -186,6 +191,9 @@
186 reverse('node-delete', args=[node.system_id]),191 reverse('node-delete', args=[node.system_id]),
187 urlparse(unicode(e)).path)192 urlparse(unicode(e)).path)
188193
194
195class TestAcceptAndCommissionNodeAction(TestCase):
196
189 def test_AcceptAndCommission_starts_commissioning(self):197 def test_AcceptAndCommission_starts_commissioning(self):
190 node = factory.make_node(198 node = factory.make_node(
191 mac=True, status=NODE_STATUS.DECLARED,199 mac=True, status=NODE_STATUS.DECLARED,
@@ -197,6 +205,9 @@
197 'provisioningserver.tasks.power_on',205 'provisioningserver.tasks.power_on',
198 self.celery.tasks[0]['task'].name)206 self.celery.tasks[0]['task'].name)
199207
208
209class TestRetryCommissioningNodeAction(TestCase):
210
200 def test_RetryCommissioning_starts_commissioning(self):211 def test_RetryCommissioning_starts_commissioning(self):
201 node = factory.make_node(212 node = factory.make_node(
202 mac=True, status=NODE_STATUS.FAILED_TESTS,213 mac=True, status=NODE_STATUS.FAILED_TESTS,
@@ -208,6 +219,9 @@
208 'provisioningserver.tasks.power_on',219 'provisioningserver.tasks.power_on',
209 self.celery.tasks[0]['task'].name)220 self.celery.tasks[0]['task'].name)
210221
222
223class TestStartNodeNodeAction(TestCase):
224
211 def test_StartNode_inhibit_allows_user_with_SSH_key(self):225 def test_StartNode_inhibit_allows_user_with_SSH_key(self):
212 user_with_key = factory.make_user()226 user_with_key = factory.make_user()
213 factory.make_sshkey(user_with_key)227 factory.make_sshkey(user_with_key)
@@ -232,3 +246,25 @@
232 self.assertEqual(246 self.assertEqual(
233 'provisioningserver.tasks.power_on',247 'provisioningserver.tasks.power_on',
234 self.celery.tasks[0]['task'].name)248 self.celery.tasks[0]['task'].name)
249
250
251class TestStopNodeNodeAction(TestCase):
252
253 def test_StopNode_stops_and_releases_node(self):
254 self.patch(PowerAction, 'run_shell', lambda *args, **kwargs: ('', ''))
255 user = factory.make_user()
256 params = dict(
257 power_address=factory.getRandomString(),
258 power_user=factory.getRandomString(),
259 power_pass=factory.getRandomString())
260 node = factory.make_node(
261 mac=True, status=NODE_STATUS.ALLOCATED,
262 power_type=POWER_TYPE.IPMI,
263 owner=user, power_parameters=params)
264 StopNode(node, user).execute()
265
266 self.assertEqual(NODE_STATUS.READY, node.status)
267 self.assertIsNone(node.owner)
268 self.assertEqual(
269 'provisioningserver.tasks.power_off',
270 self.celery.tasks[0]['task'].name)