Merge lp:~gmb/maas/acquire-and-start-node-bug-1381007 into lp:~maas-committers/maas/trunk

Proposed by Graham Binns
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 3251
Proposed branch: lp:~gmb/maas/acquire-and-start-node-bug-1381007
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 100 lines (+57/-4)
3 files modified
src/maasserver/models/tests/test_node.py (+21/-0)
src/maasserver/node_action.py (+11/-3)
src/maasserver/tests/test_node_action.py (+25/-1)
To merge this branch: bzr merge lp:~gmb/maas/acquire-and-start-node-bug-1381007
Reviewer Review Type Date Requested Status
Christian Reis (community) Approve
Review via email: mp+238279@code.launchpad.net

Commit message

Update the "Start node" button to show "Acquire and start node" only when the node is READY and there is no owner; otherwise it displays "Start node".

Previously, "Acquire and start node" would appear for admins, even when the node had been allocated.

To post a comment you must log in.
Revision history for this message
Christian Reis (kiko) wrote :

How about a test that guarantees that you can't start+allocate a node if you aren't the owner? I know the UI doesn't let you do that, but shouldn't we have an internal guarantee that we don't mess this up because the UI changed?

review: Needs Information
Revision history for this message
Graham Binns (gmb) wrote :

On 14 October 2014 12:50, Christian Reis <email address hidden> wrote:
> How about a test that guarantees that you can't start+allocate a node if you aren't the owner? I know the UI doesn't let you do that, but shouldn't we have an internal guarantee that we don't mess this up because the UI changed?

Good point. I've added two tests:

 1. To show that StartNode.execute() won't re-allocate the node when
clicked by someone (an admin) who doesn't own it.
 2. To show that NodeManager.start_nodes() won't start nodes that
don't belong to the user passed to it.

Does that cover what you're looking for?

Revision history for this message
Christian Reis (kiko) wrote :

Thanks!

It's a bit weird that it silently throws away nodes which the user doesn't own (i.e. in your first test you provide two nodes and only one comes back), enough that it might have an XXX to cover it where it's done. If you can do that approved by me.

Doing anything more than a comment is too much for 1.7.

review: Approve
Revision history for this message
Graham Binns (gmb) wrote :
Download full text (4.6 KiB)

On 14 October 2014 15:15, Christian Reis <email address hidden> wrote:
> Review: Approve
>
> Thanks!
>
> It's a bit weird that it silently throws away nodes which the user doesn't own (i.e. in your first test you provide two nodes and only one comes back), enough that it might have an XXX to cover it where it's done. If you can do that approved by me.
>
> Doing anything more than a comment is too much for 1.7.
>
> Diff comments:
>
>> === modified file 'src/maasserver/models/tests/test_node.py'
>> --- src/maasserver/models/tests/test_node.py 2014-10-14 03:50:09 +0000
>> +++ src/maasserver/models/tests/test_node.py 2014-10-14 12:16:36 +0000
>> @@ -2335,6 +2335,22 @@
>> [node1.system_id, node2.system_id], user)
>> self.assertItemsEqual([node1], nodes_started)
>>
>> + def test__does_not_try_to_start_nodes_not_allocated_to_user(self):
>> + user1 = factory.make_User()
>> + [node1] = self.make_acquired_nodes_with_macs(user1, count=1)
>> + node1.power_type = 'ether_wake' # can be started.
>> + node1.save()
>> + user2 = factory.make_User()
>> + [node2] = self.make_acquired_nodes_with_macs(user2, count=1)
>> + node2.power_type = 'ether_wake' # can be started.
>> + node2.save()
>> +
>> + self.patch(node_module, 'power_on_nodes')
>> + self.patch(node_module, 'wait_for_power_commands')
>> + nodes_started = Node.objects.start_nodes(
>> + [node1.system_id, node2.system_id], user1)
>> + self.assertItemsEqual([node1], nodes_started)
>
> ^^^

Will add.

>> +
>>
>> class NodeManagerTest_StopNodes(MAASServerTestCase):
>>
>>
>> === modified file 'src/maasserver/node_action.py'
>> --- src/maasserver/node_action.py 2014-10-13 10:40:43 +0000
>> +++ src/maasserver/node_action.py 2014-10-14 12:16:36 +0000
>> @@ -311,10 +311,18 @@
>>
>> @property
>> def display(self):
>> - if self.node.owner == self.user:
>> + # We explictly check for owner is None here, rather than owner
>> + # != self.user, because in practice the only people who are
>> + # going to see this button other than the node's owner are
>> + # administrators (because once once the node's owned, you need
>> + # EDIT permission to see this button).
>> + # We can safely assume that if you're seeing this and you don't
>> + # own the node, you're an admin, so you can still start it even
>> + # though you don't own it.
>> + if self.node.status == NODE_STATUS.READY and self.node.owner is None:
>> + label = "Acquire and start node"
>> + else:
>> label = "Start node"
>> - else:
>> - label = "Acquire and start node"
>> return label
>>
>> def inhibit(self):
>>
>> === modified file 'src/maasserver/tests/test_node_action.py'
>> --- src/maasserver/tests/test_node_action.py 2014-10-13 10:38:39 +0000
>> +++ src/maasserver/tests/test_node_action.py 2014-10-14 12:16:36 +0000
>> @@ -355,7 +355,7 @@
>> action = StartNode(node, user)
>> self.assertEqual("Acquire and start node", action.display)
>>
>> - def test_StartNode_label_hids_alloc...

Read more...

Revision history for this message
Julian Edwards (julian-edwards) wrote :

Point of order! →

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/models/tests/test_node.py'
--- src/maasserver/models/tests/test_node.py 2014-10-14 03:50:09 +0000
+++ src/maasserver/models/tests/test_node.py 2014-10-14 14:31:16 +0000
@@ -2335,6 +2335,27 @@
2335 [node1.system_id, node2.system_id], user)2335 [node1.system_id, node2.system_id], user)
2336 self.assertItemsEqual([node1], nodes_started)2336 self.assertItemsEqual([node1], nodes_started)
23372337
2338 def test__does_not_try_to_start_nodes_not_allocated_to_user(self):
2339 user1 = factory.make_User()
2340 [node1] = self.make_acquired_nodes_with_macs(user1, count=1)
2341 node1.power_type = 'ether_wake' # can be started.
2342 node1.save()
2343 user2 = factory.make_User()
2344 [node2] = self.make_acquired_nodes_with_macs(user2, count=1)
2345 node2.power_type = 'ether_wake' # can be started.
2346 node2.save()
2347
2348 self.patch(node_module, 'power_on_nodes')
2349 self.patch(node_module, 'wait_for_power_commands')
2350 nodes_started = Node.objects.start_nodes(
2351 [node1.system_id, node2.system_id], user1)
2352
2353 # Since no power commands were sent to the node, it isn't
2354 # returned by start_nodes().
2355 # test__only_returns_nodes_for_which_power_commands_have_been_sent()
2356 # demonstrates this behaviour.
2357 self.assertItemsEqual([node1], nodes_started)
2358
23382359
2339class NodeManagerTest_StopNodes(MAASServerTestCase):2360class NodeManagerTest_StopNodes(MAASServerTestCase):
23402361
23412362
=== modified file 'src/maasserver/node_action.py'
--- src/maasserver/node_action.py 2014-10-13 10:40:43 +0000
+++ src/maasserver/node_action.py 2014-10-14 14:31:16 +0000
@@ -311,10 +311,18 @@
311311
312 @property312 @property
313 def display(self):313 def display(self):
314 if self.node.owner == self.user:314 # We explictly check for owner is None here, rather than owner
315 # != self.user, because in practice the only people who are
316 # going to see this button other than the node's owner are
317 # administrators (because once once the node's owned, you need
318 # EDIT permission to see this button).
319 # We can safely assume that if you're seeing this and you don't
320 # own the node, you're an admin, so you can still start it even
321 # though you don't own it.
322 if self.node.status == NODE_STATUS.READY and self.node.owner is None:
323 label = "Acquire and start node"
324 else:
315 label = "Start node"325 label = "Start node"
316 else:
317 label = "Acquire and start node"
318 return label326 return label
319327
320 def inhibit(self):328 def inhibit(self):
321329
=== modified file 'src/maasserver/tests/test_node_action.py'
--- src/maasserver/tests/test_node_action.py 2014-10-13 10:38:39 +0000
+++ src/maasserver/tests/test_node_action.py 2014-10-14 14:31:16 +0000
@@ -355,7 +355,7 @@
355 action = StartNode(node, user)355 action = StartNode(node, user)
356 self.assertEqual("Acquire and start node", action.display)356 self.assertEqual("Acquire and start node", action.display)
357357
358 def test_StartNode_label_hids_allocate_if_allocated(self):358 def test_StartNode_label_hides_allocate_if_allocated(self):
359 self.patch(Node.objects, "start_nodes")359 self.patch(Node.objects, "start_nodes")
360 user = factory.make_User()360 user = factory.make_User()
361 node = factory.make_Node(status=NODE_STATUS.READY)361 node = factory.make_Node(status=NODE_STATUS.READY)
@@ -363,6 +363,30 @@
363 action = StartNode(node, user)363 action = StartNode(node, user)
364 self.assertEqual("Start node", action.display)364 self.assertEqual("Start node", action.display)
365365
366 def test_StartNode_label_hides_acquire_for_non_owner_admin(self):
367 user = factory.make_User()
368 admin = factory.make_admin()
369 node = factory.make_Node(status=NODE_STATUS.READY)
370 node.acquire(user)
371 action = StartNode(node, admin)
372 self.assertEqual("Start node", action.display)
373
374 def test_StartNode_does_not_reallocate_when_run_by_non_owner(self):
375 self.patch(Node.objects, "start_nodes")
376 user = factory.make_User()
377 admin = factory.make_admin()
378 node = factory.make_Node(status=NODE_STATUS.READY)
379 node.acquire(user)
380 action = StartNode(node, admin)
381
382 # This action.execute() will not fail because the non-owner is
383 # an admin, so they can start the node. Even if they weren't an
384 # admin, the node still wouldn't start;
385 # NodeManager.start_nodes() would ignore it.
386 action.execute()
387 self.assertEqual(user, node.owner)
388 self.assertEqual(NODE_STATUS.ALLOCATED, node.status)
389
366390
367class TestStopNodeNodeAction(MAASServerTestCase):391class TestStopNodeNodeAction(MAASServerTestCase):
368392