Merge ~ltrager/maas:remove_list_boot_images_v1 into maas:master

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: b63b9541f12540a117b788748e20f00ca3e10c30
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:remove_list_boot_images_v1
Merge into: maas:master
Diff against target: 424 lines (+27/-186)
7 files modified
src/maasserver/bootresources.py (+3/-9)
src/maasserver/clusterrpc/boot_images.py (+8/-29)
src/maasserver/clusterrpc/tests/test_boot_images.py (+6/-59)
src/maasserver/tests/test_bootresources.py (+4/-44)
src/provisioningserver/rpc/cluster.py (+0/-27)
src/provisioningserver/rpc/clusterservice.py (+0/-9)
src/provisioningserver/rpc/tests/test_clusterservice.py (+6/-9)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
Björn Tillenius Approve
Review via email: mp+402292@code.launchpad.net

Commit message

Remove ListBootImagesV1 RPC call.

ListBootImagesV2 was added in MAAS 1.7. Every supported version of MAAS
has the V2 call. No unsupported version of MAAS that old could connect
to a recent version of MAAS.

To post a comment you must log in.
Revision history for this message
Björn Tillenius (bjornt) wrote :

+1

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

UNIT TESTS
-b remove_list_boot_images_v1 lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: b63b9541f12540a117b788748e20f00ca3e10c30

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/bootresources.py b/src/maasserver/bootresources.py
2index 2d6aded..382fa10 100644
3--- a/src/maasserver/bootresources.py
4+++ b/src/maasserver/bootresources.py
5@@ -1,4 +1,4 @@
6-# Copyright 2014-2018 Canonical Ltd. This software is licensed under the
7+# Copyright 2014-2021 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 """Boot Resources."""
11@@ -32,7 +32,6 @@ from simplestreams.objectstores import ObjectStore
12 from twisted.application.internet import TimerService
13 from twisted.internet import reactor
14 from twisted.internet.defer import Deferred, DeferredList, inlineCallbacks
15-from twisted.protocols.amp import UnhandledCommand
16 from twisted.python.failure import Failure
17
18 from maasserver import locks
19@@ -94,7 +93,7 @@ from provisioningserver.import_images.helpers import (
20 from provisioningserver.import_images.keyrings import write_all_keyrings
21 from provisioningserver.import_images.product_mapping import map_products
22 from provisioningserver.logger import get_maas_logger, LegacyLogger
23-from provisioningserver.rpc.cluster import ListBootImages, ListBootImagesV2
24+from provisioningserver.rpc.cluster import ListBootImages
25 from provisioningserver.upgrade_cluster import create_gnupg_home
26 from provisioningserver.utils.fs import tempdir
27 from provisioningserver.utils.shell import ExternalProcessError
28@@ -1612,12 +1611,7 @@ class ImportResourcesProgressService(TimerService):
29 clients = getAllClients()
30
31 def get_images(client):
32- def fallback_v1(failure):
33- failure.trap(UnhandledCommand)
34- return client(ListBootImages)
35-
36- d = client(ListBootImagesV2)
37- d.addErrback(fallback_v1)
38+ d = client(ListBootImages)
39 d.addCallback(itemgetter("images"))
40 return d
41
42diff --git a/src/maasserver/clusterrpc/boot_images.py b/src/maasserver/clusterrpc/boot_images.py
43index 68fe1db..17573e9 100644
44--- a/src/maasserver/clusterrpc/boot_images.py
45+++ b/src/maasserver/clusterrpc/boot_images.py
46@@ -1,4 +1,4 @@
47-# Copyright 2014-2016 Canonical Ltd. This software is licensed under the
48+# Copyright 2014-2021 Canonical Ltd. This software is licensed under the
49 # GNU Affero General Public License version 3 (see the file LICENSE).
50
51 """Obtain list of boot images from rack controllers."""
52@@ -18,7 +18,6 @@ from urllib.parse import ParseResult, urlparse
53
54 from twisted.internet import reactor
55 from twisted.internet.defer import DeferredList, DeferredSemaphore
56-from twisted.protocols.amp import UnhandledCommand
57 from twisted.python.failure import Failure
58
59 from maasserver.models import BootResource, RackController
60@@ -31,7 +30,6 @@ from provisioningserver.rpc.cluster import (
61 ImportBootImages,
62 IsImportBootImagesRunning,
63 ListBootImages,
64- ListBootImagesV2,
65 )
66 from provisioningserver.rpc.exceptions import NoConnectionsAvailable
67 from provisioningserver.utils import flatten
68@@ -79,44 +77,25 @@ def get_boot_images(rack_controller):
69 30 seconds.
70 """
71 client = getClientFor(rack_controller.system_id, timeout=1)
72- try:
73- call = client(ListBootImagesV2)
74- return call.wait(30).get("images")
75- except UnhandledCommand:
76- call = client(ListBootImages)
77- return call.wait(30).get("images")
78+ call = client(ListBootImages)
79+ return call.wait(30).get("images")
80
81
82 @synchronous
83 def _get_available_boot_images():
84 """Obtain boot images available on connected rack controllers."""
85
86- def listimages_v1(client):
87+ def listimages(client):
88 return partial(client, ListBootImages)
89
90- def listimages_v2(client):
91- return partial(client, ListBootImagesV2)
92-
93- clients_v2 = getAllClients()
94- responses_v2 = gather(map(listimages_v2, clients_v2))
95- clients_v1 = []
96- for i, response in enumerate(responses_v2):
97- if (
98- isinstance(response, Failure)
99- and response.check(UnhandledCommand) is not None
100- ):
101- clients_v1.append(clients_v2[i])
102- elif not isinstance(response, Failure):
103+ clients = getAllClients()
104+ responses = gather(map(listimages, clients))
105+ for i, response in enumerate(responses):
106+ if not isinstance(response, Failure):
107 # Convert each image to a frozenset of its items.
108 yield frozenset(
109 frozenset(image.items()) for image in response["images"]
110 )
111- responses_v1 = gather(map(listimages_v1, clients_v1))
112- for response in suppress_failures(responses_v1):
113- # Convert each image to a frozenset of its items.
114- yield frozenset(
115- frozenset(image.items()) for image in response["images"]
116- )
117
118
119 @synchronous
120diff --git a/src/maasserver/clusterrpc/tests/test_boot_images.py b/src/maasserver/clusterrpc/tests/test_boot_images.py
121index 440c42c..d511c1e 100644
122--- a/src/maasserver/clusterrpc/tests/test_boot_images.py
123+++ b/src/maasserver/clusterrpc/tests/test_boot_images.py
124@@ -1,4 +1,4 @@
125-# Copyright 2014-2016 Canonical Ltd. This software is licensed under the
126+# Copyright 2014-2021 Canonical Ltd. This software is licensed under the
127 # GNU Affero General Public License version 3 (see the file LICENSE).
128
129 """Tests for the `boot_images` module."""
130@@ -6,7 +6,7 @@
131
132 import os
133 import random
134-from unittest.mock import ANY, call, MagicMock, sentinel
135+from unittest.mock import ANY, MagicMock, sentinel
136 from urllib.parse import urlparse
137
138 from testtools.matchers import (
139@@ -19,7 +19,6 @@ from testtools.matchers import (
140 )
141 from twisted.internet.defer import DeferredLock, fail, maybeDeferred, succeed
142 from twisted.internet.task import Clock
143-from twisted.protocols.amp import UnhandledCommand
144 from twisted.python.failure import Failure
145
146 from maasserver.bootresources import get_simplestream_endpoint
147@@ -50,20 +49,12 @@ from maasserver.testing.testcase import (
148 MAASServerTestCase,
149 MAASTransactionServerTestCase,
150 )
151-from maastesting.matchers import (
152- MockCalledOnceWith,
153- MockCallsMatch,
154- MockNotCalled,
155-)
156+from maastesting.matchers import MockCalledOnceWith, MockNotCalled
157 from maastesting.twisted import TwistedLoggerFixture
158 from provisioningserver.boot.tests import test_tftppath
159 from provisioningserver.boot.tftppath import compose_image_path
160 from provisioningserver.rpc import boot_images
161-from provisioningserver.rpc.cluster import (
162- ImportBootImages,
163- ListBootImages,
164- ListBootImagesV2,
165-)
166+from provisioningserver.rpc.cluster import ImportBootImages, ListBootImages
167 from provisioningserver.rpc.exceptions import NoConnectionsAvailable
168 from provisioningserver.testing.boot_images import (
169 make_boot_image_storage_params,
170@@ -158,30 +149,14 @@ class TestGetBootImages(MAASServerTestCase):
171 super().setUp()
172 prepare_tftp_root(self) # Sets self.tftp_root.
173
174- def test_calls_ListBootImagesV2_before_ListBootImages(self):
175- rack_controller = factory.make_RackController()
176- mock_client = MagicMock()
177- self.patch_autospec(
178- boot_images_module, "getClientFor"
179- ).return_value = mock_client
180- get_boot_images(rack_controller)
181- self.assertThat(mock_client, MockCalledOnceWith(ListBootImagesV2))
182-
183- def test_calls_ListBootImages_if_raised_UnhandledCommand(self):
184+ def test_calls_ListBootImages(self):
185 rack_controller = factory.make_RackController()
186 mock_client = MagicMock()
187 self.patch_autospec(
188 boot_images_module, "getClientFor"
189 ).return_value = mock_client
190- mock_client.return_value.wait.side_effect = [
191- UnhandledCommand(),
192- {"images": []},
193- ]
194 get_boot_images(rack_controller)
195- self.assertThat(
196- mock_client,
197- MockCallsMatch(call(ListBootImagesV2), call(ListBootImages)),
198- )
199+ self.assertThat(mock_client, MockCalledOnceWith(ListBootImages))
200
201
202 class TestGetBootImagesTxn(MAASTransactionServerTestCase):
203@@ -290,34 +265,6 @@ class TestGetAvailableBootImages(MAASTransactionServerTestCase):
204
205 self.assertItemsEqual(images, self.get())
206
207- def test_fallback_to_ListBootImages_on_old_clusters(self):
208- rack_1 = factory.make_RackController()
209- rack_2 = factory.make_RackController()
210- rack_3 = factory.make_RackController()
211-
212- images = [make_rpc_boot_image() for _ in range(3)]
213-
214- # Limit the region's event loop to only the "rpc" service.
215- self.useFixture(RegionEventLoopFixture("rpc"))
216- # Now start the region's event loop.
217- self.useFixture(RunningEventLoopFixture())
218- # This fixture allows us to simulate mock clusters.
219- rpc = self.useFixture(MockLiveRegionToClusterRPCFixture())
220-
221- # This simulates an older cluster, one without ListBootImagesV2.
222- rack_1 = rpc.makeCluster(rack_1, ListBootImages)
223- rack_1.ListBootImages.return_value = succeed({"images": images})
224-
225- # This simulates a newer cluster, one with ListBootImagesV2.
226- rack_2 = rpc.makeCluster(rack_2, ListBootImagesV2)
227- rack_2.ListBootImagesV2.return_value = succeed({"images": images})
228-
229- # This simulates a broken cluster.
230- rack_3 = rpc.makeCluster(rack_3, ListBootImagesV2)
231- rack_3.ListBootImagesV2.side_effect = ZeroDivisionError
232-
233- self.assertItemsEqual(images, self.get())
234-
235 def test_returns_empty_list_when_all_clusters_fail(self):
236 factory.make_RackController()
237 factory.make_RackController()
238diff --git a/src/maasserver/tests/test_bootresources.py b/src/maasserver/tests/test_bootresources.py
239index 609d784..6aa9711 100644
240--- a/src/maasserver/tests/test_bootresources.py
241+++ b/src/maasserver/tests/test_bootresources.py
242@@ -1,4 +1,4 @@
243-# Copyright 2014-2018 Canonical Ltd. This software is licensed under the
244+# Copyright 2014-2021 Canonical Ltd. This software is licensed under the
245 # GNU Affero General Public License version 3 (see the file LICENSE).
246
247 """Test maasserver.bootresources."""
248@@ -28,7 +28,6 @@ from fixtures import FakeLogger, Fixture
249 from testtools.matchers import Contains, ContainsAll, Equals, HasLength, Not
250 from twisted.application.internet import TimerService
251 from twisted.internet.defer import Deferred, fail, inlineCallbacks, succeed
252-from twisted.protocols.amp import UnhandledCommand
253
254 from maasserver import __version__, bootresources
255 from maasserver.bootresources import (
256@@ -93,7 +92,7 @@ from maastesting.testcase import MAASTestCase
257 from maastesting.twisted import extract_result, TwistedLoggerFixture
258 from provisioningserver.auth import get_maas_user_gpghome
259 from provisioningserver.import_images.product_mapping import ProductMapping
260-from provisioningserver.rpc.cluster import ListBootImages, ListBootImagesV2
261+from provisioningserver.rpc.cluster import ListBootImages
262 from provisioningserver.utils.text import normalise_whitespace
263 from provisioningserver.utils.twisted import asynchronous, DeferredValue
264
265@@ -2255,7 +2254,7 @@ class TestImportResourcesProgressServiceAsync(MAASTransactionServerTestCase):
266 factory.make_BootResource()
267 self.assertTrue(service.are_boot_images_available_in_the_region())
268
269- def test_are_boot_images_available_in_any_rack_v2(self):
270+ def test_are_boot_images_available_in_any_rack(self):
271 # Import the websocket handlers now: merely defining DeviceHandler,
272 # e.g., causes a database access, which will crash if it happens
273 # inside the reactor thread where database access is forbidden and
274@@ -2276,46 +2275,7 @@ class TestImportResourcesProgressServiceAsync(MAASTransactionServerTestCase):
275 self.assertFalse(service.are_boot_images_available_in_any_rack())
276
277 # Connect a rack controller to the region via RPC.
278- cluster_rpc = region_rpc.makeCluster(rack_controller, ListBootImagesV2)
279-
280- # are_boot_images_available_in_the_region() returns False when none of
281- # the clusters have any images.
282- cluster_rpc.ListBootImagesV2.return_value = succeed({"images": []})
283- self.assertFalse(service.are_boot_images_available_in_any_rack())
284-
285- # are_boot_images_available_in_the_region() returns True when a
286- # cluster has an imported boot image.
287- response = {"images": [make_rpc_boot_image()]}
288- cluster_rpc.ListBootImagesV2.return_value = succeed(response)
289- self.assertTrue(service.are_boot_images_available_in_any_rack())
290-
291- def test_are_boot_images_available_in_any_rack_v1(self):
292- # Import the websocket handlers now: merely defining DeviceHandler,
293- # e.g., causes a database access, which will crash if it happens
294- # inside the reactor thread where database access is forbidden and
295- # prevented. My own opinion is that a class definition should not
296- # cause a database access and we ought to fix that.
297- import maasserver.websockets.handlers # noqa
298-
299- rack_controller = factory.make_RackController()
300- service = bootresources.ImportResourcesProgressService()
301-
302- self.useFixture(RegionEventLoopFixture("rpc"))
303- self.useFixture(RunningEventLoopFixture())
304- region_rpc = MockLiveRegionToClusterRPCFixture()
305- self.useFixture(region_rpc)
306-
307- # are_boot_images_available_in_the_region() returns False when there
308- # are no clusters connected.
309- self.assertFalse(service.are_boot_images_available_in_any_rack())
310-
311- # Connect a rack controller to the region via RPC.
312- cluster_rpc = region_rpc.makeCluster(
313- rack_controller, ListBootImagesV2, ListBootImages
314- )
315-
316- # All calls to ListBootImagesV2 raises a UnhandledCommand.
317- cluster_rpc.ListBootImagesV2.side_effect = UnhandledCommand
318+ cluster_rpc = region_rpc.makeCluster(rack_controller, ListBootImages)
319
320 # are_boot_images_available_in_the_region() returns False when none of
321 # the clusters have any images.
322diff --git a/src/provisioningserver/rpc/cluster.py b/src/provisioningserver/rpc/cluster.py
323index 750ab1e..e6aa0eb 100644
324--- a/src/provisioningserver/rpc/cluster.py
325+++ b/src/provisioningserver/rpc/cluster.py
326@@ -53,33 +53,6 @@ from provisioningserver.rpc.common import Authenticate, Identify
327 class ListBootImages(amp.Command):
328 """List the boot images available on this rack controller.
329
330- :since: 1.5
331- """
332-
333- arguments = []
334- response = [
335- (
336- b"images",
337- AmpList(
338- [
339- (b"osystem", amp.Unicode()),
340- (b"architecture", amp.Unicode()),
341- (b"subarchitecture", amp.Unicode()),
342- (b"release", amp.Unicode()),
343- (b"label", amp.Unicode()),
344- (b"purpose", amp.Unicode()),
345- (b"xinstall_type", amp.Unicode()),
346- (b"xinstall_path", amp.Unicode()),
347- ]
348- ),
349- )
350- ]
351- errors = []
352-
353-
354-class ListBootImagesV2(amp.Command):
355- """List the boot images available on this rack controller.
356-
357 This command compresses the images list to allow more images in the
358 response and to remove the amp.TooLong error.
359
360diff --git a/src/provisioningserver/rpc/clusterservice.py b/src/provisioningserver/rpc/clusterservice.py
361index 0d5448b..460330a 100644
362--- a/src/provisioningserver/rpc/clusterservice.py
363+++ b/src/provisioningserver/rpc/clusterservice.py
364@@ -295,15 +295,6 @@ class Cluster(RPCProtocol):
365 """
366 return {"images": list_boot_images()}
367
368- @cluster.ListBootImagesV2.responder
369- def list_boot_images_v2(self):
370- """list_boot_images_v2()
371-
372- Implementation of
373- :py:class:`~provisioningserver.rpc.cluster.ListBootImagesV2`.
374- """
375- return {"images": list_boot_images()}
376-
377 @cluster.ImportBootImages.responder
378 def import_boot_images(self, sources, http_proxy=None, https_proxy=None):
379 """import_boot_images()
380diff --git a/src/provisioningserver/rpc/tests/test_clusterservice.py b/src/provisioningserver/rpc/tests/test_clusterservice.py
381index f71d02c..1c0e890 100644
382--- a/src/provisioningserver/rpc/tests/test_clusterservice.py
383+++ b/src/provisioningserver/rpc/tests/test_clusterservice.py
384@@ -208,18 +208,15 @@ class TestClusterProtocol_StartTLS(MAASTestCase):
385 return d.addCallback(check)
386
387
388-class TestClusterProtocol_ListBootImages_and_ListBootImagesV2(MAASTestCase):
389+class TestClusterProtocol_ListBootImages(MAASTestCase):
390
391 run_tests_with = MAASTwistedRunTest.make_factory(timeout=5)
392
393- scenarios = (
394- ("ListBootImages", {"rpc_call": cluster.ListBootImages}),
395- ("ListBootImagesV2", {"rpc_call": cluster.ListBootImagesV2}),
396- )
397-
398 def test_list_boot_images_is_registered(self):
399 protocol = Cluster()
400- responder = protocol.locateResponder(self.rpc_call.commandName)
401+ responder = protocol.locateResponder(
402+ cluster.ListBootImages.commandName
403+ )
404 self.assertIsNotNone(responder)
405
406 @inlineCallbacks
407@@ -229,7 +226,7 @@ class TestClusterProtocol_ListBootImages_and_ListBootImagesV2(MAASTestCase):
408 list_boot_images = self.patch(tftppath, "list_boot_images")
409 list_boot_images.return_value = []
410
411- response = yield call_responder(Cluster(), self.rpc_call, {})
412+ response = yield call_responder(Cluster(), cluster.ListBootImages, {})
413
414 self.assertEqual({"images": []}, response)
415
416@@ -287,7 +284,7 @@ class TestClusterProtocol_ListBootImages_and_ListBootImagesV2(MAASTestCase):
417 expected_image["xinstall_path"] = ""
418 expected_image["xinstall_type"] = ""
419
420- response = yield call_responder(Cluster(), self.rpc_call, {})
421+ response = yield call_responder(Cluster(), cluster.ListBootImages, {})
422
423 self.assertThat(response, KeysEqual("images"))
424 self.assertItemsEqual(expected_images, response["images"])

Subscribers

People subscribed via source and target branches