Merge ~ltrager/maas:remove_list_boot_images_v1 into maas:master
- Git
- lp:~ltrager/maas
- remove_list_boot_images_v1
- Merge into 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) |
Related bugs: |
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.
Description of the change
To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b remove_
STATUS: SUCCESS
COMMIT: b63b9541f12540a
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/bootresources.py b/src/maasserver/bootresources.py |
2 | index 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 | |
42 | diff --git a/src/maasserver/clusterrpc/boot_images.py b/src/maasserver/clusterrpc/boot_images.py |
43 | index 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 |
120 | diff --git a/src/maasserver/clusterrpc/tests/test_boot_images.py b/src/maasserver/clusterrpc/tests/test_boot_images.py |
121 | index 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() |
238 | diff --git a/src/maasserver/tests/test_bootresources.py b/src/maasserver/tests/test_bootresources.py |
239 | index 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. |
322 | diff --git a/src/provisioningserver/rpc/cluster.py b/src/provisioningserver/rpc/cluster.py |
323 | index 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 | |
360 | diff --git a/src/provisioningserver/rpc/clusterservice.py b/src/provisioningserver/rpc/clusterservice.py |
361 | index 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() |
380 | diff --git a/src/provisioningserver/rpc/tests/test_clusterservice.py b/src/provisioningserver/rpc/tests/test_clusterservice.py |
381 | index 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"]) |
+1