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
1=== modified file 'src/maasserver/models/tests/test_node.py'
2--- src/maasserver/models/tests/test_node.py 2014-10-14 03:50:09 +0000
3+++ src/maasserver/models/tests/test_node.py 2014-10-14 14:31:16 +0000
4@@ -2335,6 +2335,27 @@
5 [node1.system_id, node2.system_id], user)
6 self.assertItemsEqual([node1], nodes_started)
7
8+ def test__does_not_try_to_start_nodes_not_allocated_to_user(self):
9+ user1 = factory.make_User()
10+ [node1] = self.make_acquired_nodes_with_macs(user1, count=1)
11+ node1.power_type = 'ether_wake' # can be started.
12+ node1.save()
13+ user2 = factory.make_User()
14+ [node2] = self.make_acquired_nodes_with_macs(user2, count=1)
15+ node2.power_type = 'ether_wake' # can be started.
16+ node2.save()
17+
18+ self.patch(node_module, 'power_on_nodes')
19+ self.patch(node_module, 'wait_for_power_commands')
20+ nodes_started = Node.objects.start_nodes(
21+ [node1.system_id, node2.system_id], user1)
22+
23+ # Since no power commands were sent to the node, it isn't
24+ # returned by start_nodes().
25+ # test__only_returns_nodes_for_which_power_commands_have_been_sent()
26+ # demonstrates this behaviour.
27+ self.assertItemsEqual([node1], nodes_started)
28+
29
30 class NodeManagerTest_StopNodes(MAASServerTestCase):
31
32
33=== modified file 'src/maasserver/node_action.py'
34--- src/maasserver/node_action.py 2014-10-13 10:40:43 +0000
35+++ src/maasserver/node_action.py 2014-10-14 14:31:16 +0000
36@@ -311,10 +311,18 @@
37
38 @property
39 def display(self):
40- if self.node.owner == self.user:
41+ # We explictly check for owner is None here, rather than owner
42+ # != self.user, because in practice the only people who are
43+ # going to see this button other than the node's owner are
44+ # administrators (because once once the node's owned, you need
45+ # EDIT permission to see this button).
46+ # We can safely assume that if you're seeing this and you don't
47+ # own the node, you're an admin, so you can still start it even
48+ # though you don't own it.
49+ if self.node.status == NODE_STATUS.READY and self.node.owner is None:
50+ label = "Acquire and start node"
51+ else:
52 label = "Start node"
53- else:
54- label = "Acquire and start node"
55 return label
56
57 def inhibit(self):
58
59=== modified file 'src/maasserver/tests/test_node_action.py'
60--- src/maasserver/tests/test_node_action.py 2014-10-13 10:38:39 +0000
61+++ src/maasserver/tests/test_node_action.py 2014-10-14 14:31:16 +0000
62@@ -355,7 +355,7 @@
63 action = StartNode(node, user)
64 self.assertEqual("Acquire and start node", action.display)
65
66- def test_StartNode_label_hids_allocate_if_allocated(self):
67+ def test_StartNode_label_hides_allocate_if_allocated(self):
68 self.patch(Node.objects, "start_nodes")
69 user = factory.make_User()
70 node = factory.make_Node(status=NODE_STATUS.READY)
71@@ -363,6 +363,30 @@
72 action = StartNode(node, user)
73 self.assertEqual("Start node", action.display)
74
75+ def test_StartNode_label_hides_acquire_for_non_owner_admin(self):
76+ user = factory.make_User()
77+ admin = factory.make_admin()
78+ node = factory.make_Node(status=NODE_STATUS.READY)
79+ node.acquire(user)
80+ action = StartNode(node, admin)
81+ self.assertEqual("Start node", action.display)
82+
83+ def test_StartNode_does_not_reallocate_when_run_by_non_owner(self):
84+ self.patch(Node.objects, "start_nodes")
85+ user = factory.make_User()
86+ admin = factory.make_admin()
87+ node = factory.make_Node(status=NODE_STATUS.READY)
88+ node.acquire(user)
89+ action = StartNode(node, admin)
90+
91+ # This action.execute() will not fail because the non-owner is
92+ # an admin, so they can start the node. Even if they weren't an
93+ # admin, the node still wouldn't start;
94+ # NodeManager.start_nodes() would ignore it.
95+ action.execute()
96+ self.assertEqual(user, node.owner)
97+ self.assertEqual(NODE_STATUS.ALLOCATED, node.status)
98+
99
100 class TestStopNodeNodeAction(MAASServerTestCase):
101