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
=== modified file 'src/maasserver/models/node.py'
--- src/maasserver/models/node.py 2016-05-09 21:18:43 +0000
+++ src/maasserver/models/node.py 2016-05-10 23:45:39 +0000
@@ -162,6 +162,7 @@
162from provisioningserver.power import QUERY_POWER_TYPES162from provisioningserver.power import QUERY_POWER_TYPES
163from provisioningserver.rpc.cluster import (163from provisioningserver.rpc.cluster import (
164 AddChassis,164 AddChassis,
165 DisableAndShutoffRackd,
165 IsImportBootImagesRunning,166 IsImportBootImagesRunning,
166 RefreshRackControllerInfo,167 RefreshRackControllerInfo,
167)168)
@@ -3658,15 +3659,6 @@
36583659
3659 def delete(self):3660 def delete(self):
3660 """Delete this rack controller."""3661 """Delete this rack controller."""
3661 # Avoid circular dependency.
3662 from maasserver.models import RegionRackRPCConnection
3663 connections = RegionRackRPCConnection.objects.filter(
3664 rack_controller=self)
3665 if len(connections) != 0:
3666 raise ValidationError(
3667 "Unable to delete %s as it's currently connected to one or "
3668 "more regions." % self.hostname)
3669
3670 primary_vlans = VLAN.objects.filter(primary_rack=self)3662 primary_vlans = VLAN.objects.filter(primary_rack=self)
3671 if len(primary_vlans) != 0:3663 if len(primary_vlans) != 0:
3672 raise ValidationError(3664 raise ValidationError(
@@ -3675,6 +3667,15 @@
3675 (self.hostname,3667 (self.hostname,
3676 ', '.join([str(vlan) for vlan in primary_vlans])))3668 ', '.join([str(vlan) for vlan in primary_vlans])))
36773669
3670 try:
3671 client = getClientFor(self.system_id, timeout=1)
3672 call = client(DisableAndShutoffRackd)
3673 call.wait(30)
3674 except NoConnectionsAvailable:
3675 # NoConnectionsAvailable is always thrown. Either because the rack
3676 # is currently disconnected or rackd was killed
3677 pass
3678
3678 for vlan in VLAN.objects.filter(secondary_rack=self):3679 for vlan in VLAN.objects.filter(secondary_rack=self):
3679 vlan.secondary_rack = None3680 vlan.secondary_rack = None
3680 vlan.save()3681 vlan.save()
36813682
=== modified file 'src/maasserver/models/tests/test_node.py'
--- src/maasserver/models/tests/test_node.py 2016-05-09 23:54:19 +0000
+++ src/maasserver/models/tests/test_node.py 2016-05-10 23:45:39 +0000
@@ -137,10 +137,12 @@
137from provisioningserver.power.schema import JSON_POWER_TYPE_PARAMETERS137from provisioningserver.power.schema import JSON_POWER_TYPE_PARAMETERS
138from provisioningserver.rpc.cluster import (138from provisioningserver.rpc.cluster import (
139 AddChassis,139 AddChassis,
140 DisableAndShutoffRackd,
140 IsImportBootImagesRunning,141 IsImportBootImagesRunning,
141 RefreshRackControllerInfo,142 RefreshRackControllerInfo,
142)143)
143from provisioningserver.rpc.exceptions import (144from provisioningserver.rpc.exceptions import (
145 CannotDisableAndShutoffRackd,
144 NoConnectionsAvailable,146 NoConnectionsAvailable,
145 UnknownPowerType,147 UnknownPowerType,
146)148)
@@ -6992,11 +6994,34 @@
6992 rackcontroller.delete()6994 rackcontroller.delete()
6993 self.assertIsNone(reload_object(rackcontroller))6995 self.assertIsNone(reload_object(rackcontroller))
69946996
6995 def test_prevents_delete_when_connected(self):6997 def test_disables_and_disconn_when_secondary_connected(self):
6996 rackcontroller = factory.make_RackController()6998 rackcontroller = factory.make_RackController()
6997 mock_filter = self.patch(RegionRackRPCConnection.objects, 'filter')6999 factory.make_VLAN(secondary_rack=rackcontroller)
6998 mock_filter.return_value = [rackcontroller]7000
6999 self.assertRaises(ValidationError, rackcontroller.delete)7001 self.useFixture(RegionEventLoopFixture("rpc"))
7002 self.useFixture(RunningEventLoopFixture())
7003 fixture = self.useFixture(MockLiveRegionToClusterRPCFixture())
7004 protocol = fixture.makeCluster(
7005 rackcontroller, DisableAndShutoffRackd)
7006 protocol.DisableAndShutoffRackd.return_value = defer.succeed({})
7007
7008 rackcontroller.delete()
7009 self.expectThat(protocol.DisableAndShutoffRackd, MockCalledOnce())
7010
7011 def test_disables_and_disconn_when_secondary_connected_fails(self):
7012 rackcontroller = factory.make_RackController()
7013 factory.make_VLAN(secondary_rack=rackcontroller)
7014
7015 self.useFixture(RegionEventLoopFixture("rpc"))
7016 self.useFixture(RunningEventLoopFixture())
7017 fixture = self.useFixture(MockLiveRegionToClusterRPCFixture())
7018 protocol = fixture.makeCluster(
7019 rackcontroller, DisableAndShutoffRackd)
7020 protocol.DisableAndShutoffRackd.return_value = defer.fail(
7021 CannotDisableAndShutoffRackd())
7022
7023 self.assertRaises(CannotDisableAndShutoffRackd, rackcontroller.delete)
7024 self.expectThat(protocol.DisableAndShutoffRackd, MockCalledOnce())
70007025
7001 def test_prevents_delete_when_primary_rack(self):7026 def test_prevents_delete_when_primary_rack(self):
7002 rackcontroller = factory.make_RackController()7027 rackcontroller = factory.make_RackController()
70037028
=== modified file 'src/provisioningserver/rpc/cluster.py'
--- src/provisioningserver/rpc/cluster.py 2016-04-29 22:12:18 +0000
+++ src/provisioningserver/rpc/cluster.py 2016-05-10 23:45:39 +0000
@@ -478,3 +478,15 @@
478 (b"protocol", amp.Unicode(optional=True)),478 (b"protocol", amp.Unicode(optional=True)),
479 ]479 ]
480 errors = {}480 errors = {}
481
482
483class DisableAndShutoffRackd(amp.Command):
484 """Disable and shutdown the rackd service.
485
486 :since: 2.0
487 """
488 arguments = []
489 errors = {
490 exceptions.CannotDisableAndShutoffRackd: (
491 b"CannotDisableAndShutoffRackd"),
492 }
481493
=== modified file 'src/provisioningserver/rpc/clusterservice.py'
--- src/provisioningserver/rpc/clusterservice.py 2016-04-29 22:12:18 +0000
+++ src/provisioningserver/rpc/clusterservice.py 2016-05-10 23:45:39 +0000
@@ -72,6 +72,10 @@
72 get_maas_id,72 get_maas_id,
73 set_maas_id,73 set_maas_id,
74)74)
75from provisioningserver.utils.shell import (
76 call_and_check,
77 ExternalProcessError,
78)
75from provisioningserver.utils.twisted import (79from provisioningserver.utils.twisted import (
76 DeferredValue,80 DeferredValue,
77 synchronous,81 synchronous,
@@ -460,6 +464,26 @@
460 maaslog.error(message)464 maaslog.error(message)
461 return {}465 return {}
462466
467 @cluster.DisableAndShutoffRackd.responder
468 def disable_and_shutoff_rackd(self):
469 """DisableAndShutoffRackd()
470
471 Implementation of
472 :py:class:`~provisioningserver.rpc.cluster.DisableAndShutoffRackd`.
473 """
474 maaslog.info("Rack deleted, disabling rackd service")
475 try:
476 # We can't use the --now flag as if the maas-rackd service is on
477 # but not enabled the service won't be stopped
478 call_and_check(
479 ['sudo', 'systemctl', 'disable', 'maas-rackd'])
480 call_and_check(
481 ['sudo', 'systemctl', 'stop', 'maas-rackd'])
482 except ExternalProcessError as e:
483 maaslog.error("Unable to disable and stop maas-rackd service")
484 raise exceptions.CannotDisableAndShutoffRackd(e.output_as_unicode)
485 return {}
486
463487
464@implementer(IConnection)488@implementer(IConnection)
465class ClusterClient(Cluster):489class ClusterClient(Cluster):
466490
=== modified file 'src/provisioningserver/rpc/exceptions.py'
--- src/provisioningserver/rpc/exceptions.py 2016-04-11 16:23:26 +0000
+++ src/provisioningserver/rpc/exceptions.py 2016-05-10 23:45:39 +0000
@@ -7,6 +7,7 @@
7 "AuthenticationFailed",7 "AuthenticationFailed",
8 "CannotConfigureDHCP",8 "CannotConfigureDHCP",
9 "CannotCreateHostMap",9 "CannotCreateHostMap",
10 "CannotDisableAndShutoffRackd",
10 "CannotModifyHostMap",11 "CannotModifyHostMap",
11 "CannotRegisterCluster",12 "CannotRegisterCluster",
12 "CannotRemoveHostMap",13 "CannotRemoveHostMap",
@@ -146,3 +147,7 @@
146147
147class BootConfigNoResponse(Exception):148class BootConfigNoResponse(Exception):
148 """The region gave no response for the boot configuration."""149 """The region gave no response for the boot configuration."""
150
151
152class CannotDisableAndShutoffRackd(Exception):
153 """Rackd cannot be disabled and shutoff."""
149154
=== modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py'
--- src/provisioningserver/rpc/tests/test_clusterservice.py 2016-05-10 11:02:10 +0000
+++ src/provisioningserver/rpc/tests/test_clusterservice.py 2016-05-10 23:45:39 +0000
@@ -2392,3 +2392,28 @@
2392 'hostname': factory.make_hostname(),2392 'hostname': factory.make_hostname(),
2393 })2393 })
2394 self.assertEquals({}, response.result)2394 self.assertEquals({}, response.result)
2395
2396
2397class TestClusterProtocol_DisableAndShutoffRackd(MAASTestCase):
2398
2399 def test__is_registered(self):
2400 protocol = Cluster()
2401 responder = protocol.locateResponder(
2402 cluster.DisableAndShutoffRackd.commandName)
2403 self.assertIsNotNone(responder)
2404
2405 def test_issues_restart(self):
2406 mock_call_and_check = self.patch(clusterservice, 'call_and_check')
2407 response = call_responder(
2408 Cluster(), cluster.DisableAndShutoffRackd, {})
2409 self.assertEquals({}, response.result)
2410 self.assertEquals(2, mock_call_and_check.call_count)
2411
2412 @inlineCallbacks
2413 def test_raises_error_on_failure(self):
2414 mock_call_and_check = self.patch(clusterservice, 'call_and_check')
2415 mock_call_and_check.side_effect = ExternalProcessError(
2416 1, 'systemctl', 'failure')
2417 with ExpectedException(exceptions.CannotDisableAndShutoffRackd):
2418 yield call_responder(
2419 Cluster(), cluster.DisableAndShutoffRackd, {})