Merge lp:~newell-jensen/maas/2.2-fix-1694759 into lp:maas/2.2

Proposed by Newell Jensen
Status: Merged
Approved by: Mike Pontillo
Approved revision: no longer in the source branch.
Merged at revision: 6062
Proposed branch: lp:~newell-jensen/maas/2.2-fix-1694759
Merge into: lp:maas/2.2
Diff against target: 235 lines (+85/-72)
2 files modified
src/provisioningserver/drivers/pod/rsd.py (+14/-10)
src/provisioningserver/drivers/pod/tests/test_rsd.py (+71/-62)
To merge this branch: bzr merge lp:~newell-jensen/maas/2.2-fix-1694759
Reviewer Review Type Date Requested Status
Newell Jensen (community) Approve
Review via email: mp+325260@code.launchpad.net

Commit message

Backport trunk r6074: Delete newly allocated RSD node if the assembling process fails.

To post a comment you must log in.
Revision history for this message
Newell Jensen (newell-jensen) wrote :

Self review backport.

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

The attempt to merge lp:~newell-jensen/maas/2.2-fix-1694759 into lp:maas/2.2 failed. Below is the output from the failed tests.

Hit:1 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Hit:2 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:3 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu xenial-security InRelease
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind avahi-utils 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 isc-dhcp-server libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libnss-wrapper libpq-dev make nodejs-legacy npm postgresql psmisc pxelinux python3-all python3-apt python3-attr python3-bson python3-convoy 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...
authbind is already the newest version (2.1.1+nmu1).
avahi-utils is already the newest version (0.6.32~rc+dfsg-1ubuntu2).
build-essential is already the newest version (12.1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
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).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
psmisc is already the newest version (22.21-2.1build1).
pxelinux is already the newest version (3:6.03+dfsg-11ubuntu1).
python-formencode is already the newest version (1.3.0-0ubuntu5).
python-lxml is already the newest version (3.5.0-1build1).
python-netaddr is already the newest version (0.7.18-1).
python-netifaces is already the newest version (0.10.4-0.1build2).
python-psycopg2 is already the newest version (2.6.1-1...

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

The attempt to merge lp:~newell-jensen/maas/2.2-fix-1694759 into lp:maas/2.2 failed. Below is the output from the failed tests.

Hit:1 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Get:4 http://prodstack-zone-1.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB]
Fetched 306 kB in 0s (336 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind avahi-utils 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 isc-dhcp-server libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libnss-wrapper libpq-dev make nodejs-legacy npm postgresql psmisc pxelinux python3-all python3-apt python3-attr python3-bson python3-convoy 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...
authbind is already the newest version (2.1.1+nmu1).
avahi-utils is already the newest version (0.6.32~rc+dfsg-1ubuntu2).
build-essential is already the newest version (12.1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
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).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
psmisc is already the newest version (22.21-2.1build1).
pxelinux is already the newest version (3:6.03+dfsg-11ubuntu1).
python-formencode is already the newest version (1.3.0-0ubuntu5).
python-lxml is already the newest version (3.5.0-1build1).
python-netaddr is already the newest version (0.7.18-1).
python-netifaces is already the newest version (0.10.4-0.1buil...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/provisioningserver/drivers/pod/rsd.py'
--- src/provisioningserver/drivers/pod/rsd.py 2017-05-09 19:10:12 +0000
+++ src/provisioningserver/drivers/pod/rsd.py 2017-06-07 17:24:55 +0000
@@ -1046,11 +1046,8 @@
1046 "Unable to allocate machine with requested resources.")1046 "Unable to allocate machine with requested resources.")
10471047
1048 @inlineCallbacks1048 @inlineCallbacks
1049 def decompose(self, pod_id, context):1049 def delete_node(self, url, node_id, headers):
1050 """Decompose machine."""1050 """Delete node at node_id."""
1051 url = self.get_url(context)
1052 node_id = context.get('node_id').encode('utf-8')
1053 headers = self.make_auth_headers(**context)
1054 # Delete machine at node_id.1051 # Delete machine at node_id.
1055 endpoint = b"redfish/v1/Nodes/%s" % node_id1052 endpoint = b"redfish/v1/Nodes/%s" % node_id
1056 try:1053 try:
@@ -1060,12 +1057,17 @@
1060 # XXX newell 2017-02-27 bug=1667754:1057 # XXX newell 2017-02-27 bug=1667754:
1061 # Catch the 404 error when trying to decompose the1058 # Catch the 404 error when trying to decompose the
1062 # resource that has already been decomposed.1059 # resource that has already been decomposed.
1063 # This is a work around and will need to be handled
1064 # differently on the region so we don't try to
1065 # decompose a machine multiple times.
1066 if int(error.status) != HTTPStatus.NOT_FOUND:1060 if int(error.status) != HTTPStatus.NOT_FOUND:
1067 raise1061 raise
10681062
1063 @inlineCallbacks
1064 def decompose(self, pod_id, context):
1065 """Decompose machine."""
1066 url = self.get_url(context)
1067 node_id = context.get('node_id').encode('utf-8')
1068 headers = self.make_auth_headers(**context)
1069 yield self.delete_node(url, node_id, headers)
1070
1069 # Retrieve pod resources.1071 # Retrieve pod resources.
1070 discovered_pod = yield self.get_pod_resources(url, headers)1072 discovered_pod = yield self.get_pod_resources(url, headers)
1071 # Retrive pod hints.1073 # Retrive pod hints.
@@ -1114,7 +1116,8 @@
1114 yield self.redfish_request(1116 yield self.redfish_request(
1115 b"POST", join(url, endpoint), headers)1117 b"POST", join(url, endpoint), headers)
1116 elif node_state == 'Failed':1118 elif node_state == 'Failed':
1117 # Broken system.1119 # Broken system, delete allocated node.
1120 yield self.delete_node(url, node_id, headers)
1118 raise PodFatalError(1121 raise PodFatalError(
1119 "Composed machine at node ID %s has a ComposedNodeState"1122 "Composed machine at node ID %s has a ComposedNodeState"
1120 " of Failed." % node_id)1123 " of Failed." % node_id)
@@ -1131,7 +1134,8 @@
1131 # Check one last time if the state has became `Failed`.1134 # Check one last time if the state has became `Failed`.
11321135
1133 if node_state == 'Failed':1136 if node_state == 'Failed':
1134 # Broken system.1137 # Broken system, delete allocated node.
1138 yield self.delete_node(url, node_id, headers)
1135 raise PodFatalError(1139 raise PodFatalError(
1136 "Composed machine at node ID %s has a ComposedNodeState"1140 "Composed machine at node ID %s has a ComposedNodeState"
1137 " of Failed." % node_id)1141 " of Failed." % node_id)
11381142
=== modified file 'src/provisioningserver/drivers/pod/tests/test_rsd.py'
--- src/provisioningserver/drivers/pod/tests/test_rsd.py 2017-05-09 21:53:26 +0000
+++ src/provisioningserver/drivers/pod/tests/test_rsd.py 2017-06-07 17:24:55 +0000
@@ -2002,74 +2002,77 @@
2002 factory.make_name('system_id'), context, request)2002 factory.make_name('system_id'), context, request)
20032003
2004 @inlineCallbacks2004 @inlineCallbacks
2005 def test__delete_node(self):
2006 driver = RSDPodDriver()
2007 context = make_context()
2008 url = driver.get_url(context)
2009 node_id = context.get('node_id').encode('utf-8')
2010 endpoint = b"redfish/v1/Nodes/%s" % node_id
2011 headers = driver.make_auth_headers(**context)
2012 mock_redfish_request = self.patch(driver, 'redfish_request')
2013
2014 yield driver.delete_node(url, node_id, headers)
2015 self.assertThat(mock_redfish_request, MockCalledOnceWith(
2016 b"DELETE", join(url, endpoint), headers))
2017
2018 @inlineCallbacks
2019 def test_delete_node_continues_on_404_error(self):
2020 driver = RSDPodDriver()
2021 context = make_context()
2022 url = driver.get_url(context)
2023 node_id = context.get('node_id').encode('utf-8')
2024 endpoint = b"redfish/v1/Nodes/%s" % node_id
2025 headers = driver.make_auth_headers(**context)
2026 mock_redfish_request = self.patch(driver, 'redfish_request')
2027 error = PartialDownloadError(
2028 response=json.dumps(SAMPLE_JSON_SYSTEMS).encode('utf-8'),
2029 code=HTTPStatus.NOT_FOUND)
2030 mock_redfish_request.side_effect = error
2031
2032 yield driver.delete_node(url, node_id, headers)
2033 self.assertThat(mock_redfish_request, MockCalledOnceWith(
2034 b"DELETE", join(url, endpoint), headers))
2035
2036 @inlineCallbacks
2037 def test_delete_node_raises_when_not_404_error(self):
2038 driver = RSDPodDriver()
2039 context = make_context()
2040 url = driver.get_url(context)
2041 node_id = context.get('node_id').encode('utf-8')
2042 endpoint = b"redfish/v1/Nodes/%s" % node_id
2043 headers = driver.make_auth_headers(**context)
2044 mock_redfish_request = self.patch(driver, 'redfish_request')
2045 error = PartialDownloadError(
2046 response=json.dumps(SAMPLE_JSON_SYSTEMS).encode('utf-8'),
2047 code=HTTPStatus.BAD_REQUEST)
2048 mock_redfish_request.side_effect = error
2049
2050 with ExpectedException(PartialDownloadError):
2051 yield driver.delete_node(url, node_id, headers)
2052 self.assertThat(mock_redfish_request, MockCalledOnceWith(
2053 b"DELETE", join(url, endpoint), headers))
2054
2055 @inlineCallbacks
2005 def test__decompose(self):2056 def test__decompose(self):
2006 driver = RSDPodDriver()2057 driver = RSDPodDriver()
2007 context = make_context()2058 context = make_context()
2008 url = driver.get_url(context)2059 url = driver.get_url(context)
2009 node_id = context.get('node_id').encode('utf-8')2060 node_id = context.get('node_id').encode('utf-8')
2010 headers = driver.make_auth_headers(**context)2061 headers = driver.make_auth_headers(**context)
2011 endpoint = b"redfish/v1/Nodes/%s" % node_id2062 mock_delete_node = self.patch(driver, 'delete_node')
2012 mock_redfish_request = self.patch(driver, 'redfish_request')2063 mock_get_pod_resources = self.patch(driver, 'get_pod_resources')
2013 mock_get_pod_resources = self.patch(driver, 'get_pod_resources')2064 discovered_pod = make_discovered_pod()
2014 discovered_pod = make_discovered_pod()2065 mock_get_pod_resources.return_value = discovered_pod
2015 mock_get_pod_resources.return_value = discovered_pod2066 mock_get_pod_hints = self.patch(driver, 'get_pod_hints')
2016 mock_get_pod_hints = self.patch(driver, 'get_pod_hints')2067
20172068 yield driver.decompose(
2018 yield driver.decompose(2069 factory.make_name('system_id'), context)
2019 factory.make_name('system_id'), context)2070 self.assertThat(mock_delete_node, MockCalledOnceWith(
2020 self.assertThat(mock_redfish_request, MockCalledOnceWith(2071 url, node_id, headers))
2021 b"DELETE", join(url, endpoint), headers))2072 self.assertThat(mock_get_pod_resources, MockCalledOnceWith(
2022 self.assertThat(mock_get_pod_resources, MockCalledOnceWith(2073 url, headers))
2023 url, headers))2074 self.assertThat(mock_get_pod_hints, MockCalledOnceWith(
2024 self.assertThat(mock_get_pod_hints, MockCalledOnceWith(2075 discovered_pod))
2025 discovered_pod))
2026
2027 @inlineCallbacks
2028 def test_decompose_continues_on_404_error(self):
2029 driver = RSDPodDriver()
2030 context = make_context()
2031 url = driver.get_url(context)
2032 node_id = context.get('node_id').encode('utf-8')
2033 headers = driver.make_auth_headers(**context)
2034 endpoint = b"redfish/v1/Nodes/%s" % node_id
2035 mock_redfish_request = self.patch(driver, 'redfish_request')
2036 error = PartialDownloadError(
2037 response=json.dumps(SAMPLE_JSON_SYSTEMS).encode('utf-8'),
2038 code=HTTPStatus.NOT_FOUND)
2039 mock_redfish_request.side_effect = error
2040 mock_get_pod_resources = self.patch(driver, 'get_pod_resources')
2041 discovered_pod = make_discovered_pod()
2042 mock_get_pod_resources.return_value = discovered_pod
2043 mock_get_pod_hints = self.patch(driver, 'get_pod_hints')
2044
2045 yield driver.decompose(
2046 factory.make_name('system_id'), context)
2047 self.assertThat(mock_redfish_request, MockCalledOnceWith(
2048 b"DELETE", join(url, endpoint), headers))
2049 self.assertThat(mock_get_pod_resources, MockCalledOnceWith(
2050 url, headers))
2051 self.assertThat(mock_get_pod_hints, MockCalledOnceWith(
2052 discovered_pod))
2053
2054 @inlineCallbacks
2055 def test_decompose_raises_when_not_404_error(self):
2056 driver = RSDPodDriver()
2057 context = make_context()
2058 url = driver.get_url(context)
2059 node_id = context.get('node_id').encode('utf-8')
2060 headers = driver.make_auth_headers(**context)
2061 endpoint = b"redfish/v1/Nodes/%s" % node_id
2062 mock_redfish_request = self.patch(driver, 'redfish_request')
2063 error = PartialDownloadError(
2064 response=json.dumps(SAMPLE_JSON_SYSTEMS).encode('utf-8'),
2065 code=HTTPStatus.BAD_REQUEST)
2066 mock_redfish_request.side_effect = error
2067
2068 with ExpectedException(PartialDownloadError):
2069 yield driver.decompose(
2070 factory.make_name('system_id'), context)
2071 self.assertThat(mock_redfish_request, MockCalledOnceWith(
2072 b"DELETE", join(url, endpoint), headers))
20732076
2074 @inlineCallbacks2077 @inlineCallbacks
2075 def test__set_pxe_boot(self):2078 def test__set_pxe_boot(self):
@@ -2164,12 +2167,15 @@
2164 mock_get_composed_node_state = self.patch(2167 mock_get_composed_node_state = self.patch(
2165 driver, 'get_composed_node_state')2168 driver, 'get_composed_node_state')
2166 mock_get_composed_node_state.return_value = "Failed"2169 mock_get_composed_node_state.return_value = "Failed"
2170 mock_delete_node = self.patch(driver, 'delete_node')
2167 mock_redfish_request = self.patch(driver, 'redfish_request')2171 mock_redfish_request = self.patch(driver, 'redfish_request')
21682172
2169 with ExpectedException(PodFatalError):2173 with ExpectedException(PodFatalError):
2170 yield driver.assemble_node(url, node_id, headers)2174 yield driver.assemble_node(url, node_id, headers)
2171 self.assertThat(mock_get_composed_node_state, MockCalledOnceWith(2175 self.assertThat(mock_get_composed_node_state, MockCalledOnceWith(
2172 url, node_id, headers))2176 url, node_id, headers))
2177 self.assertThat(mock_delete_node, MockCalledOnceWith(
2178 url, node_id, headers))
2173 self.assertThat(mock_redfish_request, MockNotCalled())2179 self.assertThat(mock_redfish_request, MockNotCalled())
21742180
2175 @inlineCallbacks2181 @inlineCallbacks
@@ -2183,6 +2189,7 @@
2183 driver, 'get_composed_node_state')2189 driver, 'get_composed_node_state')
2184 mock_get_composed_node_state.side_effect = [2190 mock_get_composed_node_state.side_effect = [
2185 "Allocated", "Assembling", "Failed"]2191 "Allocated", "Assembling", "Failed"]
2192 mock_delete_node = self.patch(driver, 'delete_node')
2186 mock_redfish_request = self.patch(driver, 'redfish_request')2193 mock_redfish_request = self.patch(driver, 'redfish_request')
2187 endpoint = (2194 endpoint = (
2188 b"redfish/v1/Nodes/%s/Actions/ComposedNode.Assemble" % node_id)2195 b"redfish/v1/Nodes/%s/Actions/ComposedNode.Assemble" % node_id)
@@ -2196,6 +2203,8 @@
2196 call(url, node_id, headers)))2203 call(url, node_id, headers)))
2197 self.assertThat(mock_redfish_request, MockCalledOnceWith(2204 self.assertThat(mock_redfish_request, MockCalledOnceWith(
2198 b"POST", uri, headers))2205 b"POST", uri, headers))
2206 self.assertThat(mock_delete_node, MockCalledOnceWith(
2207 url, node_id, headers))
21992208
2200 @inlineCallbacks2209 @inlineCallbacks
2201 def test_power_issues_power_reset(self):2210 def test_power_issues_power_reset(self):

Subscribers

People subscribed via source and target branches

to all changes: