Merge lp:~ltrager/maas/mark_broken_fixed_machine_only into lp:~maas-committers/maas/trunk

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: no longer in the source branch.
Merged at revision: 4991
Proposed branch: lp:~ltrager/maas/mark_broken_fixed_machine_only
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 484 lines (+182/-172)
7 files modified
src/maasserver/api/machines.py (+43/-0)
src/maasserver/api/nodes.py (+0/-44)
src/maasserver/api/tests/test_machine.py (+131/-0)
src/maasserver/api/tests/test_machines.py (+5/-5)
src/maasserver/api/tests/test_node.py (+0/-120)
src/maasserver/node_action.py (+2/-2)
src/maasserver/websockets/handlers/tests/test_general.py (+1/-1)
To merge this branch: bzr merge lp:~ltrager/maas/mark_broken_fixed_machine_only
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+293701@code.launchpad.net

Commit message

Only show mark broken/fixed on machines.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good. Simple code moving.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1.1 MiB)

The attempt to merge lp:~ltrager/maas/mark_broken_fixed_machine_only into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [92.2 kB]
Hit:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [93.3 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:5 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/main Sources [11.4 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [36.9 kB]
Get:7 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/main Translation-en [14.0 kB]
Get:8 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [9,012 B]
Get:9 http://security.ubuntu.com/ubuntu xenial-security/main Sources [6,264 B]
Get:10 http://security.ubuntu.com/ubuntu xenial-security/main amd64 Packages [27.7 kB]
Get:11 http://security.ubuntu.com/ubuntu xenial-security/main Translation-en [9,264 B]
Fetched 300 kB in 0s (597 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bash bind9 bind9utils build-essential bzr bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-2ubuntu3).
archdetect-deb is already the newest version (1.117ubuntu2).
authbind is already the newest version (2.1.1+nmu1).
bash is already the newest version (4.3-14ubuntu1).
build-essential is already the newest version (12.1ubuntu2).
bzr is already the newest version (2.7.0-2ubuntu1).
curl is already the newest version (7.47.0-1ubun...

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1.1 MiB)

The attempt to merge lp:~ltrager/maas/mark_broken_fixed_machine_only into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [92.2 kB]
Hit:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [93.3 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 185 kB in 0s (396 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bash bind9 bind9utils build-essential bzr bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-2ubuntu3).
archdetect-deb is already the newest version (1.117ubuntu2).
authbind is already the newest version (2.1.1+nmu1).
bash is already the newest version (4.3-14ubuntu1).
build-essential is already the newest version (12.1ubuntu2).
bzr is already the newest version (2.7.0-2ubuntu1).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
freeipmi-tools is already the newest version (1.4.11-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
isc-dhcp-common is already the newest version (4.3.3-5ubuntu12).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
libpq-dev is already the newest version (9.5.2-1).
make is already the newest version (4.1-6).
postgresql is already the new...

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1.1 MiB)

The attempt to merge lp:~ltrager/maas/mark_broken_fixed_machine_only into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [93.3 kB]
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:4 http://security.ubuntu.com/ubuntu xenial-security InRelease [92.2 kB]
Fetched 185 kB in 0s (398 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bash bind9 bind9utils build-essential bzr bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-2ubuntu3).
archdetect-deb is already the newest version (1.117ubuntu2).
authbind is already the newest version (2.1.1+nmu1).
bash is already the newest version (4.3-14ubuntu1).
build-essential is already the newest version (12.1ubuntu2).
bzr is already the newest version (2.7.0-2ubuntu1).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
freeipmi-tools is already the newest version (1.4.11-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
isc-dhcp-common is already the newest version (4.3.3-5ubuntu12).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
libpq-dev is already the newest version (9.5.2-1).
make is already the newest version (4.1-6).
postgresql is already the new...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/machines.py'
2--- src/maasserver/api/machines.py 2016-04-28 01:11:50 +0000
3+++ src/maasserver/api/machines.py 2016-05-04 21:03:37 +0000
4@@ -582,6 +582,49 @@
5 get_curtin_merged_config(machine), default_flow_style=False),
6 content_type='text/plain')
7
8+ @operation(idempotent=False)
9+ def mark_broken(self, request, system_id):
10+ """Mark a node as 'broken'.
11+
12+ If the node is allocated, release it first.
13+
14+ :param comment: Optional comment for the event log. Will be
15+ displayed on the node as an error description until marked fixed.
16+ :type comment: unicode
17+
18+ Returns 404 if the node is not found.
19+ Returns 403 if the user does not have permission to mark the node
20+ broken.
21+ """
22+ node = self.model.objects.get_node_or_404(
23+ user=request.user, system_id=system_id, perm=NODE_PERMISSION.EDIT)
24+ comment = get_optional_param(request.POST, 'comment')
25+ if not comment:
26+ # read old error_description to for backward compatibility
27+ comment = get_optional_param(request.POST, 'error_description')
28+ node.mark_broken(request.user, comment)
29+ return node
30+
31+ @operation(idempotent=False)
32+ def mark_fixed(self, request, system_id):
33+ """Mark a broken node as fixed and set its status as 'ready'.
34+
35+ :param comment: Optional comment for the event log.
36+ :type comment: unicode
37+
38+ Returns 404 if the machine is not found.
39+ Returns 403 if the user does not have permission to mark the machine
40+ fixed.
41+ """
42+ comment = get_optional_param(request.POST, 'comment')
43+ node = self.model.objects.get_node_or_404(
44+ user=request.user, system_id=system_id, perm=NODE_PERMISSION.ADMIN)
45+ node.mark_fixed(request.user, comment)
46+ maaslog.info(
47+ "%s: User %s marked node as fixed", node.hostname,
48+ request.user.username)
49+ return node
50+
51
52 def create_machine(request):
53 """Service an http request to create a machine.
54
55=== modified file 'src/maasserver/api/nodes.py'
56--- src/maasserver/api/nodes.py 2016-04-28 01:11:50 +0000
57+++ src/maasserver/api/nodes.py 2016-05-04 21:03:37 +0000
58@@ -15,7 +15,6 @@
59 import bson
60 from django.http import HttpResponse
61 from django.shortcuts import get_object_or_404
62-from maasserver.api.logger import maaslog
63 from maasserver.api.support import (
64 admin_method,
65 AnonymousOperationsHandler,
66@@ -498,49 +497,6 @@
67 else:
68 return None
69
70- @operation(idempotent=False)
71- def mark_broken(self, request, system_id):
72- """Mark a node as 'broken'.
73-
74- If the node is allocated, release it first.
75-
76- :param comment: Optional comment for the event log. Will be
77- displayed on the node as an error description until marked fixed.
78- :type comment: unicode
79-
80- Returns 404 if the node is not found.
81- Returns 403 if the user does not have permission to mark the node
82- broken.
83- """
84- node = self.model.objects.get_node_or_404(
85- user=request.user, system_id=system_id, perm=NODE_PERMISSION.EDIT)
86- comment = get_optional_param(request.POST, 'comment')
87- if not comment:
88- # read old error_description to for backward compatibility
89- comment = get_optional_param(request.POST, 'error_description')
90- node.mark_broken(request.user, comment)
91- return node
92-
93- @operation(idempotent=False)
94- def mark_fixed(self, request, system_id):
95- """Mark a broken node as fixed and set its status as 'ready'.
96-
97- :param comment: Optional comment for the event log.
98- :type comment: unicode
99-
100- Returns 404 if the machine is not found.
101- Returns 403 if the user does not have permission to mark the machine
102- fixed.
103- """
104- comment = get_optional_param(request.POST, 'comment')
105- node = self.model.objects.get_node_or_404(
106- user=request.user, system_id=system_id, perm=NODE_PERMISSION.ADMIN)
107- node.mark_fixed(request.user, comment)
108- maaslog.info(
109- "%s: User %s marked node as fixed", node.hostname,
110- request.user.username)
111- return node
112-
113
114 class PowersMixin:
115 """Mixin which adds power commands to a nodes type."""
116
117=== modified file 'src/maasserver/api/tests/test_machine.py'
118--- src/maasserver/api/tests/test_machine.py 2016-04-28 01:11:50 +0000
119+++ src/maasserver/api/tests/test_machine.py 2016-05-04 21:03:37 +0000
120@@ -1883,3 +1883,134 @@
121 response.content.decode(settings.DEFAULT_CHARSET))
122 self.assertThat(
123 mock_get_curtin_merged_config, MockCalledOnceWith(machine))
124+
125+
126+class TestMarkBroken(APITestCase):
127+
128+ def get_node_uri(self, machine):
129+ """Get the API URI for `machine`."""
130+ return reverse('machine_handler', args=[machine.system_id])
131+
132+ def test_mark_broken_changes_status(self):
133+ node = factory.make_Node(
134+ status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
135+ response = self.client.post(
136+ self.get_node_uri(node), {'op': 'mark_broken'})
137+ self.assertEqual(http.client.OK, response.status_code)
138+ self.assertEqual(NODE_STATUS.BROKEN, reload_object(node).status)
139+
140+ def test_mark_broken_updates_error_description(self):
141+ # 'error_description' parameter was renamed 'comment' for consistency
142+ # make sure this comment updates the node's error_description
143+ node = factory.make_Node(
144+ status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
145+ comment = factory.make_name('comment')
146+ response = self.client.post(
147+ self.get_node_uri(node),
148+ {'op': 'mark_broken', 'comment': comment})
149+ self.assertEqual(http.client.OK, response.status_code)
150+ node = reload_object(node)
151+ self.assertEqual(
152+ (NODE_STATUS.BROKEN, comment),
153+ (node.status, node.error_description)
154+ )
155+
156+ def test_mark_broken_updates_error_description_compatibility(self):
157+ # test old 'error_description' parameter is honored for compatibility
158+ node = factory.make_Node(
159+ status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
160+ error_description = factory.make_name('error_description')
161+ response = self.client.post(
162+ self.get_node_uri(node),
163+ {'op': 'mark_broken', 'error_description': error_description})
164+ self.assertEqual(http.client.OK, response.status_code)
165+ node = reload_object(node)
166+ self.assertEqual(
167+ (NODE_STATUS.BROKEN, error_description),
168+ (node.status, node.error_description)
169+ )
170+
171+ def test_mark_broken_passes_comment(self):
172+ node = factory.make_Node(
173+ status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
174+ node_mark_broken = self.patch(node_module.Machine, 'mark_broken')
175+ comment = factory.make_name('comment')
176+ self.client.post(
177+ self.get_node_uri(node),
178+ {'op': 'mark_broken', 'comment': comment})
179+ self.assertThat(
180+ node_mark_broken,
181+ MockCalledOnceWith(self.logged_in_user, comment))
182+
183+ def test_mark_broken_handles_missing_comment(self):
184+ node = factory.make_Node(
185+ status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
186+ node_mark_broken = self.patch(node_module.Machine, 'mark_broken')
187+ self.client.post(
188+ self.get_node_uri(node), {'op': 'mark_broken'})
189+ self.assertThat(
190+ node_mark_broken,
191+ MockCalledOnceWith(self.logged_in_user, None))
192+
193+ def test_mark_broken_requires_ownership(self):
194+ node = factory.make_Node(status=NODE_STATUS.COMMISSIONING)
195+ response = self.client.post(
196+ self.get_node_uri(node), {'op': 'mark_broken'})
197+ self.assertEqual(http.client.FORBIDDEN, response.status_code)
198+
199+ def test_mark_broken_allowed_from_any_other_state(self):
200+ self.patch(node_module.Machine, "_stop")
201+ for status, _ in NODE_STATUS_CHOICES:
202+ if status == NODE_STATUS.BROKEN:
203+ continue
204+
205+ node = factory.make_Node(status=status, owner=self.logged_in_user)
206+ response = self.client.post(
207+ self.get_node_uri(node), {'op': 'mark_broken'})
208+ self.expectThat(
209+ response.status_code, Equals(http.client.OK), response)
210+ node = reload_object(node)
211+ self.expectThat(node.status, Equals(NODE_STATUS.BROKEN))
212+
213+
214+class TestMarkFixed(APITestCase):
215+
216+ def get_node_uri(self, machine):
217+ """Get the API URI for `machine`."""
218+ return reverse('machine_handler', args=[machine.system_id])
219+
220+ def test_mark_fixed_changes_status(self):
221+ self.become_admin()
222+ node = factory.make_Node(status=NODE_STATUS.BROKEN)
223+ response = self.client.post(
224+ self.get_node_uri(node), {'op': 'mark_fixed'})
225+ self.assertEqual(http.client.OK, response.status_code)
226+ self.assertEqual(NODE_STATUS.READY, reload_object(node).status)
227+
228+ def test_mark_fixed_requires_admin(self):
229+ node = factory.make_Node(status=NODE_STATUS.BROKEN)
230+ response = self.client.post(
231+ self.get_node_uri(node), {'op': 'mark_fixed'})
232+ self.assertEqual(http.client.FORBIDDEN, response.status_code)
233+
234+ def test_mark_fixed_passes_comment(self):
235+ self.become_admin()
236+ node = factory.make_Node(status=NODE_STATUS.BROKEN)
237+ node_mark_fixed = self.patch(node_module.Machine, 'mark_fixed')
238+ comment = factory.make_name('comment')
239+ self.client.post(
240+ self.get_node_uri(node),
241+ {'op': 'mark_fixed', 'comment': comment})
242+ self.assertThat(
243+ node_mark_fixed,
244+ MockCalledOnceWith(self.logged_in_user, comment))
245+
246+ def test_mark_fixed_handles_missing_comment(self):
247+ self.become_admin()
248+ node = factory.make_Node(status=NODE_STATUS.BROKEN)
249+ node_mark_fixed = self.patch(node_module.Machine, 'mark_fixed')
250+ self.client.post(
251+ self.get_node_uri(node), {'op': 'mark_fixed'})
252+ self.assertThat(
253+ node_mark_fixed,
254+ MockCalledOnceWith(self.logged_in_user, None))
255
256=== modified file 'src/maasserver/api/tests/test_machines.py'
257--- src/maasserver/api/tests/test_machines.py 2016-04-28 01:11:50 +0000
258+++ src/maasserver/api/tests/test_machines.py 2016-05-04 21:03:37 +0000
259@@ -1146,7 +1146,7 @@
260 self.become_admin()
261 target_state = NODE_STATUS.COMMISSIONING
262
263- self.patch(Node, "_start").return_value = None
264+ self.patch(Machine, "_start").return_value = None
265 machine = factory.make_Node_with_Interface_on_Subnet(
266 status=NODE_STATUS.NEW)
267 response = self.client.post(
268@@ -1244,7 +1244,7 @@
269 self.become_admin()
270 target_state = NODE_STATUS.COMMISSIONING
271
272- self.patch(Node, "_start").return_value = None
273+ self.patch(Machine, "_start").return_value = None
274 machines = [
275 factory.make_Node_with_Interface_on_Subnet(status=NODE_STATUS.NEW)
276 for counter in range(2)]
277@@ -1260,7 +1260,7 @@
278
279 def test_POST_accept_returns_actually_accepted_machines(self):
280 self.become_admin()
281- self.patch(Node, "_start").return_value = None
282+ self.patch(Machine, "_start").return_value = None
283 acceptable_machines = [
284 factory.make_Node_with_Interface_on_Subnet(status=NODE_STATUS.NEW)
285 for counter in range(2)
286@@ -1383,7 +1383,7 @@
287
288 def test_POST_release_returns_modified_machines(self):
289 owner = self.logged_in_user
290- self.patch(Node, "_stop").return_value = None
291+ self.patch(Machine, "_stop").return_value = None
292 acceptable_states = [NODE_STATUS.READY] + RELEASABLE_STATUSES
293 machines = [
294 factory.make_Node_with_Interface_on_Subnet(
295@@ -1405,7 +1405,7 @@
296
297 def test_POST_release_erases_disks_when_enabled(self):
298 owner = self.logged_in_user
299- self.patch(Node, "_start").return_value = None
300+ self.patch(Machine, "_start").return_value = None
301 machine = factory.make_Node_with_Interface_on_Subnet(
302 status=NODE_STATUS.ALLOCATED, power_state=POWER_STATE.OFF,
303 owner=owner)
304
305=== modified file 'src/maasserver/api/tests/test_node.py'
306--- src/maasserver/api/tests/test_node.py 2016-04-28 01:11:50 +0000
307+++ src/maasserver/api/tests/test_node.py 2016-05-04 21:03:37 +0000
308@@ -12,7 +12,6 @@
309 from django.core.urlresolvers import reverse
310 from maasserver.enum import (
311 NODE_STATUS,
312- NODE_STATUS_CHOICES,
313 POWER_STATE,
314 )
315 from maasserver.models import (
316@@ -26,9 +25,7 @@
317 from maasserver.testing.osystems import make_usable_osystem
318 from maasserver.testing.testcase import MAASServerTestCase
319 from maasserver.utils.converters import json_load_bytes
320-from maasserver.utils.orm import reload_object
321 from maastesting.matchers import (
322- Equals,
323 MockCalledOnceWith,
324 MockNotCalled,
325 )
326@@ -493,123 +490,6 @@
327 self.assertEqual(
328 machine.system_id, json_load_bytes(response.content)['system_id'])
329
330- def test_mark_broken_changes_status(self):
331- node = factory.make_Node(
332- status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
333- response = self.client.post(
334- self.get_node_uri(node), {'op': 'mark_broken'})
335- self.assertEqual(http.client.OK, response.status_code)
336- self.assertEqual(NODE_STATUS.BROKEN, reload_object(node).status)
337-
338- def test_mark_broken_updates_error_description(self):
339- # 'error_description' parameter was renamed 'comment' for consistency
340- # make sure this comment updates the node's error_description
341- node = factory.make_Node(
342- status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
343- comment = factory.make_name('comment')
344- response = self.client.post(
345- self.get_node_uri(node),
346- {'op': 'mark_broken', 'comment': comment})
347- self.assertEqual(http.client.OK, response.status_code)
348- node = reload_object(node)
349- self.assertEqual(
350- (NODE_STATUS.BROKEN, comment),
351- (node.status, node.error_description)
352- )
353-
354- def test_mark_broken_updates_error_description_compatibility(self):
355- # test old 'error_description' parameter is honored for compatibility
356- node = factory.make_Node(
357- status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
358- error_description = factory.make_name('error_description')
359- response = self.client.post(
360- self.get_node_uri(node),
361- {'op': 'mark_broken', 'error_description': error_description})
362- self.assertEqual(http.client.OK, response.status_code)
363- node = reload_object(node)
364- self.assertEqual(
365- (NODE_STATUS.BROKEN, error_description),
366- (node.status, node.error_description)
367- )
368-
369- def test_mark_broken_passes_comment(self):
370- node = factory.make_Node(
371- status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
372- node_mark_broken = self.patch(node_module.Machine, 'mark_broken')
373- comment = factory.make_name('comment')
374- self.client.post(
375- self.get_node_uri(node),
376- {'op': 'mark_broken', 'comment': comment})
377- self.assertThat(
378- node_mark_broken,
379- MockCalledOnceWith(self.logged_in_user, comment))
380-
381- def test_mark_broken_handles_missing_comment(self):
382- node = factory.make_Node(
383- status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
384- node_mark_broken = self.patch(node_module.Machine, 'mark_broken')
385- self.client.post(
386- self.get_node_uri(node), {'op': 'mark_broken'})
387- self.assertThat(
388- node_mark_broken,
389- MockCalledOnceWith(self.logged_in_user, None))
390-
391- def test_mark_broken_requires_ownership(self):
392- node = factory.make_Node(status=NODE_STATUS.COMMISSIONING)
393- response = self.client.post(
394- self.get_node_uri(node), {'op': 'mark_broken'})
395- self.assertEqual(http.client.FORBIDDEN, response.status_code)
396-
397- def test_mark_broken_allowed_from_any_other_state(self):
398- self.patch(node_module.Machine, "_stop")
399- for status, _ in NODE_STATUS_CHOICES:
400- if status == NODE_STATUS.BROKEN:
401- continue
402-
403- node = factory.make_Node(status=status, owner=self.logged_in_user)
404- response = self.client.post(
405- self.get_node_uri(node), {'op': 'mark_broken'})
406- self.expectThat(
407- response.status_code, Equals(http.client.OK), response)
408- node = reload_object(node)
409- self.expectThat(node.status, Equals(NODE_STATUS.BROKEN))
410-
411- def test_mark_fixed_changes_status(self):
412- self.become_admin()
413- node = factory.make_Node(status=NODE_STATUS.BROKEN)
414- response = self.client.post(
415- self.get_node_uri(node), {'op': 'mark_fixed'})
416- self.assertEqual(http.client.OK, response.status_code)
417- self.assertEqual(NODE_STATUS.READY, reload_object(node).status)
418-
419- def test_mark_fixed_requires_admin(self):
420- node = factory.make_Node(status=NODE_STATUS.BROKEN)
421- response = self.client.post(
422- self.get_node_uri(node), {'op': 'mark_fixed'})
423- self.assertEqual(http.client.FORBIDDEN, response.status_code)
424-
425- def test_mark_fixed_passes_comment(self):
426- self.become_admin()
427- node = factory.make_Node(status=NODE_STATUS.BROKEN)
428- node_mark_fixed = self.patch(node_module.Machine, 'mark_fixed')
429- comment = factory.make_name('comment')
430- self.client.post(
431- self.get_node_uri(node),
432- {'op': 'mark_fixed', 'comment': comment})
433- self.assertThat(
434- node_mark_fixed,
435- MockCalledOnceWith(self.logged_in_user, comment))
436-
437- def test_mark_fixed_handles_missing_comment(self):
438- self.become_admin()
439- node = factory.make_Node(status=NODE_STATUS.BROKEN)
440- node_mark_fixed = self.patch(node_module.Machine, 'mark_fixed')
441- self.client.post(
442- self.get_node_uri(node), {'op': 'mark_fixed'})
443- self.assertThat(
444- node_mark_fixed,
445- MockCalledOnceWith(self.logged_in_user, None))
446-
447 def test_query_power_state(self):
448 node = factory.make_Node()
449 mock__power_control_node = self.patch(
450
451=== modified file 'src/maasserver/node_action.py'
452--- src/maasserver/node_action.py 2016-04-29 19:31:59 +0000
453+++ src/maasserver/node_action.py 2016-05-04 21:03:37 +0000
454@@ -426,7 +426,7 @@
455 NODE_STATUS.DISK_ERASING,
456 ] + FAILED_STATUSES
457 permission = NODE_PERMISSION.EDIT
458- for_type = {NODE_TYPE.MACHINE, NODE_TYPE.RACK_CONTROLLER}
459+ for_type = {NODE_TYPE.MACHINE}
460
461 def execute(self):
462 """See `NodeAction.execute`."""
463@@ -440,7 +440,7 @@
464 display_sentence = "marked fixed"
465 actionable_statuses = (NODE_STATUS.BROKEN, )
466 permission = NODE_PERMISSION.ADMIN
467- for_type = {NODE_TYPE.MACHINE, NODE_TYPE.RACK_CONTROLLER}
468+ for_type = {NODE_TYPE.MACHINE}
469
470 def execute(self):
471 """See `NodeAction.execute`."""
472
473=== modified file 'src/maasserver/websockets/handlers/tests/test_general.py'
474--- src/maasserver/websockets/handlers/tests/test_general.py 2016-05-02 12:47:22 +0000
475+++ src/maasserver/websockets/handlers/tests/test_general.py 2016-05-04 21:03:37 +0000
476@@ -142,7 +142,7 @@
477 def test_rack_controller_actions_for_admin(self):
478 handler = GeneralHandler(factory.make_admin(), {})
479 self.assertItemsEqual(
480- ['delete', 'mark-broken', 'mark-fixed', 'off', 'on', 'set-zone'],
481+ ['delete', 'off', 'on', 'set-zone'],
482 [action['name'] for action in handler.rack_controller_actions({})])
483
484 def test_rack_controller_actions_for_non_admin(self):