Merge lp:~ltrager/maas/disable_delete_rack 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: 5011
Proposed branch: lp:~ltrager/maas/disable_delete_rack
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~ltrager/maas/delete_rack
Diff against target: 215 lines (+106/-14)
6 files modified
src/maasserver/models/node.py (+10/-9)
src/maasserver/models/tests/test_node.py (+30/-5)
src/provisioningserver/rpc/cluster.py (+12/-0)
src/provisioningserver/rpc/clusterservice.py (+24/-0)
src/provisioningserver/rpc/exceptions.py (+5/-0)
src/provisioningserver/rpc/tests/test_clusterservice.py (+25/-0)
To merge this branch: bzr merge lp:~ltrager/maas/disable_delete_rack
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+293594@code.launchpad.net

Commit message

Disable and stop the rackd service if running on deletion

Description of the change

Upon deletion of a rack controller if a secondary rack controller is still connected send an RPC call which disables and stops the maas-rackd service. A user can reenable it using systemctl. As maas-dhcpd{,6}.service is bound to maas-rackd.service stopping maas-rackd also stops maas-dhcpd{,6}.

Last Friday when testing this branch the delete failed because there still was a relation between the rack controller and RegionRackRPCConnection. Since merging trunk I haven't seen this error but I'm wondering if I should search and delete any of these relations.

For maas-rackd to be able to disable and stop the maas-rackd service I had to add permission to 99-maas-sudoers. Review at https://code.launchpad.net/~ltrager/maas/disable_delete_rackd_sudo/+merge/293593

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

This looks really good. Nice work.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

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

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

Hit:1 http://security.ubuntu.com/ubuntu xenial-security InRelease
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 [94.5 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 94.5 kB in 0s (179 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 newest version (9.5+173...

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

The attempt to merge lp:~ltrager/maas/disable_delete_rack 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
Hit:2 http://security.ubuntu.com/ubuntu xenial-security InRelease
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [94.5 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 94.5 kB in 0s (217 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 newest version (9.5+173...

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

The attempt to merge lp:~ltrager/maas/disable_delete_rack 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 [94.5 kB]
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu xenial-security InRelease
Get:5 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [64.3 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [15.0 kB]
Fetched 174 kB in 0s (397 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-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).
l...

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

The attempt to merge lp:~ltrager/maas/disable_delete_rack 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 [94.5 kB]
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu xenial-security InRelease
Fetched 94.5 kB in 0s (231 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-netaddr python3-netifaces python3-novaclient 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 newest version (9...

Revision history for this message
Andres Rodriguez (andreserl) wrote :

ERROR: provisioningserver.rpc.tests.test_clusterservice.TestClusterProtocol_Identify.test_identify_is_registered
----------------------------------------------------------------------
testtools.testresult.real._StringException: logged-error: {{{
Traceback (most recent call last):
provisioningserver.rpc.exceptions.CannotDisableAndShutoffRackd: failure
}}}

twisted-log: {{{
2016-05-10 18:30:20+0000 [-] Unhandled error in Deferred:
2016-05-10 18:30:20+0000 [-] Unhandled Error
 Traceback (most recent call last):
 Failure: provisioningserver.rpc.exceptions.CannotDisableAndShutoffRackd: failure
}}}

----------------------------------------------------------------------
Ran 2369 tests in 44.324s

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/models/node.py'
2--- src/maasserver/models/node.py 2016-05-09 21:18:43 +0000
3+++ src/maasserver/models/node.py 2016-05-10 23:45:39 +0000
4@@ -162,6 +162,7 @@
5 from provisioningserver.power import QUERY_POWER_TYPES
6 from provisioningserver.rpc.cluster import (
7 AddChassis,
8+ DisableAndShutoffRackd,
9 IsImportBootImagesRunning,
10 RefreshRackControllerInfo,
11 )
12@@ -3658,15 +3659,6 @@
13
14 def delete(self):
15 """Delete this rack controller."""
16- # Avoid circular dependency.
17- from maasserver.models import RegionRackRPCConnection
18- connections = RegionRackRPCConnection.objects.filter(
19- rack_controller=self)
20- if len(connections) != 0:
21- raise ValidationError(
22- "Unable to delete %s as it's currently connected to one or "
23- "more regions." % self.hostname)
24-
25 primary_vlans = VLAN.objects.filter(primary_rack=self)
26 if len(primary_vlans) != 0:
27 raise ValidationError(
28@@ -3675,6 +3667,15 @@
29 (self.hostname,
30 ', '.join([str(vlan) for vlan in primary_vlans])))
31
32+ try:
33+ client = getClientFor(self.system_id, timeout=1)
34+ call = client(DisableAndShutoffRackd)
35+ call.wait(30)
36+ except NoConnectionsAvailable:
37+ # NoConnectionsAvailable is always thrown. Either because the rack
38+ # is currently disconnected or rackd was killed
39+ pass
40+
41 for vlan in VLAN.objects.filter(secondary_rack=self):
42 vlan.secondary_rack = None
43 vlan.save()
44
45=== modified file 'src/maasserver/models/tests/test_node.py'
46--- src/maasserver/models/tests/test_node.py 2016-05-09 23:54:19 +0000
47+++ src/maasserver/models/tests/test_node.py 2016-05-10 23:45:39 +0000
48@@ -137,10 +137,12 @@
49 from provisioningserver.power.schema import JSON_POWER_TYPE_PARAMETERS
50 from provisioningserver.rpc.cluster import (
51 AddChassis,
52+ DisableAndShutoffRackd,
53 IsImportBootImagesRunning,
54 RefreshRackControllerInfo,
55 )
56 from provisioningserver.rpc.exceptions import (
57+ CannotDisableAndShutoffRackd,
58 NoConnectionsAvailable,
59 UnknownPowerType,
60 )
61@@ -6992,11 +6994,34 @@
62 rackcontroller.delete()
63 self.assertIsNone(reload_object(rackcontroller))
64
65- def test_prevents_delete_when_connected(self):
66- rackcontroller = factory.make_RackController()
67- mock_filter = self.patch(RegionRackRPCConnection.objects, 'filter')
68- mock_filter.return_value = [rackcontroller]
69- self.assertRaises(ValidationError, rackcontroller.delete)
70+ def test_disables_and_disconn_when_secondary_connected(self):
71+ rackcontroller = factory.make_RackController()
72+ factory.make_VLAN(secondary_rack=rackcontroller)
73+
74+ self.useFixture(RegionEventLoopFixture("rpc"))
75+ self.useFixture(RunningEventLoopFixture())
76+ fixture = self.useFixture(MockLiveRegionToClusterRPCFixture())
77+ protocol = fixture.makeCluster(
78+ rackcontroller, DisableAndShutoffRackd)
79+ protocol.DisableAndShutoffRackd.return_value = defer.succeed({})
80+
81+ rackcontroller.delete()
82+ self.expectThat(protocol.DisableAndShutoffRackd, MockCalledOnce())
83+
84+ def test_disables_and_disconn_when_secondary_connected_fails(self):
85+ rackcontroller = factory.make_RackController()
86+ factory.make_VLAN(secondary_rack=rackcontroller)
87+
88+ self.useFixture(RegionEventLoopFixture("rpc"))
89+ self.useFixture(RunningEventLoopFixture())
90+ fixture = self.useFixture(MockLiveRegionToClusterRPCFixture())
91+ protocol = fixture.makeCluster(
92+ rackcontroller, DisableAndShutoffRackd)
93+ protocol.DisableAndShutoffRackd.return_value = defer.fail(
94+ CannotDisableAndShutoffRackd())
95+
96+ self.assertRaises(CannotDisableAndShutoffRackd, rackcontroller.delete)
97+ self.expectThat(protocol.DisableAndShutoffRackd, MockCalledOnce())
98
99 def test_prevents_delete_when_primary_rack(self):
100 rackcontroller = factory.make_RackController()
101
102=== modified file 'src/provisioningserver/rpc/cluster.py'
103--- src/provisioningserver/rpc/cluster.py 2016-04-29 22:12:18 +0000
104+++ src/provisioningserver/rpc/cluster.py 2016-05-10 23:45:39 +0000
105@@ -478,3 +478,15 @@
106 (b"protocol", amp.Unicode(optional=True)),
107 ]
108 errors = {}
109+
110+
111+class DisableAndShutoffRackd(amp.Command):
112+ """Disable and shutdown the rackd service.
113+
114+ :since: 2.0
115+ """
116+ arguments = []
117+ errors = {
118+ exceptions.CannotDisableAndShutoffRackd: (
119+ b"CannotDisableAndShutoffRackd"),
120+ }
121
122=== modified file 'src/provisioningserver/rpc/clusterservice.py'
123--- src/provisioningserver/rpc/clusterservice.py 2016-04-29 22:12:18 +0000
124+++ src/provisioningserver/rpc/clusterservice.py 2016-05-10 23:45:39 +0000
125@@ -72,6 +72,10 @@
126 get_maas_id,
127 set_maas_id,
128 )
129+from provisioningserver.utils.shell import (
130+ call_and_check,
131+ ExternalProcessError,
132+)
133 from provisioningserver.utils.twisted import (
134 DeferredValue,
135 synchronous,
136@@ -460,6 +464,26 @@
137 maaslog.error(message)
138 return {}
139
140+ @cluster.DisableAndShutoffRackd.responder
141+ def disable_and_shutoff_rackd(self):
142+ """DisableAndShutoffRackd()
143+
144+ Implementation of
145+ :py:class:`~provisioningserver.rpc.cluster.DisableAndShutoffRackd`.
146+ """
147+ maaslog.info("Rack deleted, disabling rackd service")
148+ try:
149+ # We can't use the --now flag as if the maas-rackd service is on
150+ # but not enabled the service won't be stopped
151+ call_and_check(
152+ ['sudo', 'systemctl', 'disable', 'maas-rackd'])
153+ call_and_check(
154+ ['sudo', 'systemctl', 'stop', 'maas-rackd'])
155+ except ExternalProcessError as e:
156+ maaslog.error("Unable to disable and stop maas-rackd service")
157+ raise exceptions.CannotDisableAndShutoffRackd(e.output_as_unicode)
158+ return {}
159+
160
161 @implementer(IConnection)
162 class ClusterClient(Cluster):
163
164=== modified file 'src/provisioningserver/rpc/exceptions.py'
165--- src/provisioningserver/rpc/exceptions.py 2016-04-11 16:23:26 +0000
166+++ src/provisioningserver/rpc/exceptions.py 2016-05-10 23:45:39 +0000
167@@ -7,6 +7,7 @@
168 "AuthenticationFailed",
169 "CannotConfigureDHCP",
170 "CannotCreateHostMap",
171+ "CannotDisableAndShutoffRackd",
172 "CannotModifyHostMap",
173 "CannotRegisterCluster",
174 "CannotRemoveHostMap",
175@@ -146,3 +147,7 @@
176
177 class BootConfigNoResponse(Exception):
178 """The region gave no response for the boot configuration."""
179+
180+
181+class CannotDisableAndShutoffRackd(Exception):
182+ """Rackd cannot be disabled and shutoff."""
183
184=== modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py'
185--- src/provisioningserver/rpc/tests/test_clusterservice.py 2016-05-10 11:02:10 +0000
186+++ src/provisioningserver/rpc/tests/test_clusterservice.py 2016-05-10 23:45:39 +0000
187@@ -2392,3 +2392,28 @@
188 'hostname': factory.make_hostname(),
189 })
190 self.assertEquals({}, response.result)
191+
192+
193+class TestClusterProtocol_DisableAndShutoffRackd(MAASTestCase):
194+
195+ def test__is_registered(self):
196+ protocol = Cluster()
197+ responder = protocol.locateResponder(
198+ cluster.DisableAndShutoffRackd.commandName)
199+ self.assertIsNotNone(responder)
200+
201+ def test_issues_restart(self):
202+ mock_call_and_check = self.patch(clusterservice, 'call_and_check')
203+ response = call_responder(
204+ Cluster(), cluster.DisableAndShutoffRackd, {})
205+ self.assertEquals({}, response.result)
206+ self.assertEquals(2, mock_call_and_check.call_count)
207+
208+ @inlineCallbacks
209+ def test_raises_error_on_failure(self):
210+ mock_call_and_check = self.patch(clusterservice, 'call_and_check')
211+ mock_call_and_check.side_effect = ExternalProcessError(
212+ 1, 'systemctl', 'failure')
213+ with ExpectedException(exceptions.CannotDisableAndShutoffRackd):
214+ yield call_responder(
215+ Cluster(), cluster.DisableAndShutoffRackd, {})