~blake-rouse/maas/action-styles-update-1.8

« back to all changes in this revision

Viewing changes to src/maasserver/clusterrpc/tests/test_boot_images.py

  • Committer: MAAS Lander
  • Author(s): Blake Rouse
  • Date: 2015-08-03 18:20:55 UTC
  • mfrom: (4032.1.1 1.8)
  • Revision ID: maas_lander-20150803182055-8boe370rdp99dskb
[r=blake-rouse][bug=1472707][author=blake-rouse] Add ListBootImagesV2 RPC command. Fallback to using ListBootImages RPC when the ListBootImagesV2 is not handled on the cluster.

The signature of the ListBootImages RPC call was changed to support more data in the response. This change will cause connected clusters that are not updated the same time as the region to stop communicating and error. This allows both methods to exist on the cluster where V2 will be called first then fallback to the older call in error.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import os
18
18
 
 
19
from maasserver.clusterrpc import boot_images as boot_images_module
19
20
from maasserver.clusterrpc.boot_images import (
20
21
    get_available_boot_images,
21
22
    get_boot_images,
29
30
    NODEGROUP_STATUS,
30
31
)
31
32
from maasserver.rpc import getAllClients
32
 
from maasserver.rpc.testing.fixtures import RunningClusterRPCFixture
 
33
from maasserver.rpc.testing.fixtures import (
 
34
    MockLiveRegionToClusterRPCFixture,
 
35
    RunningClusterRPCFixture,
 
36
)
 
37
from maasserver.testing.eventloop import (
 
38
    RegionEventLoopFixture,
 
39
    RunningEventLoopFixture,
 
40
)
33
41
from maasserver.testing.factory import factory
34
42
from maasserver.testing.testcase import MAASServerTestCase
 
43
from maastesting.matchers import (
 
44
    MockCalledOnceWith,
 
45
    MockCallsMatch,
 
46
)
 
47
from mock import (
 
48
    call,
 
49
    MagicMock,
 
50
)
35
51
from provisioningserver.boot.tests import test_tftppath
36
52
from provisioningserver.boot.tftppath import (
37
53
    compose_image_path,
41
57
    boot_images,
42
58
    clusterservice,
43
59
)
 
60
from provisioningserver.rpc.cluster import (
 
61
    ListBootImages,
 
62
    ListBootImagesV2,
 
63
)
44
64
from provisioningserver.testing.boot_images import (
45
65
    make_boot_image_storage_params,
46
66
    make_image,
47
67
)
48
68
from twisted.internet.defer import succeed
 
69
from twisted.protocols.amp import UnhandledCommand
49
70
 
50
71
 
51
72
def make_image_dir(image_params, tftproot):
164
185
            ],
165
186
            get_boot_images(nodegroup))
166
187
 
 
188
    def test_calls_ListBootImagesV2_before_ListBootImages(self):
 
189
        nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
 
190
        mock_client = MagicMock()
 
191
        self.patch_autospec(
 
192
            boot_images_module, "getClientFor").return_value = mock_client
 
193
        get_boot_images(nodegroup)
 
194
        self.assertThat(mock_client, MockCalledOnceWith(ListBootImagesV2))
 
195
 
 
196
    def test_calls_ListBootImages_if_raised_UnhandledCommand(self):
 
197
        nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
 
198
        mock_client = MagicMock()
 
199
        self.patch_autospec(
 
200
            boot_images_module, "getClientFor").return_value = mock_client
 
201
        mock_client.return_value.wait.side_effect = [
 
202
            UnhandledCommand(),
 
203
            {"images": []},
 
204
            ]
 
205
        get_boot_images(nodegroup)
 
206
        self.assertThat(mock_client, MockCallsMatch(
 
207
            call(ListBootImagesV2),
 
208
            call(ListBootImages)))
 
209
 
167
210
 
168
211
class TestGetAvailableBootImages(MAASServerTestCase):
169
212
    """Tests for `get_available_boot_images`."""
239
282
            images,
240
283
            get_available_boot_images())
241
284
 
 
285
    def test_fallback_to_ListBootImages_on_old_clusters(self):
 
286
        nodegroup_1 = factory.make_NodeGroup()
 
287
        nodegroup_1.accept()
 
288
        nodegroup_2 = factory.make_NodeGroup()
 
289
        nodegroup_2.accept()
 
290
        nodegroup_3 = factory.make_NodeGroup()
 
291
        nodegroup_3.accept()
 
292
 
 
293
        images = [make_rpc_boot_image() for _ in range(3)]
 
294
 
 
295
        # Limit the region's event loop to only the "rpc" service.
 
296
        self.useFixture(RegionEventLoopFixture("rpc"))
 
297
        # Now start the region's event loop.
 
298
        self.useFixture(RunningEventLoopFixture())
 
299
        # This fixture allows us to simulate mock clusters.
 
300
        rpc = self.useFixture(MockLiveRegionToClusterRPCFixture())
 
301
 
 
302
        # This simulates an older cluster, one without ListBootImagesV2.
 
303
        cluster_1 = rpc.makeCluster(nodegroup_1, ListBootImages)
 
304
        cluster_1.ListBootImages.return_value = succeed({'images': images})
 
305
 
 
306
        # This simulates a newer cluster, one with ListBootImagesV2.
 
307
        cluster_2 = rpc.makeCluster(nodegroup_2, ListBootImagesV2)
 
308
        cluster_2.ListBootImagesV2.return_value = succeed({'images': images})
 
309
 
 
310
        # This simulates a broken cluster.
 
311
        cluster_3 = rpc.makeCluster(nodegroup_3, ListBootImagesV2)
 
312
        cluster_3.ListBootImagesV2.side_effect = ZeroDivisionError
 
313
 
 
314
        self.assertItemsEqual(images, get_available_boot_images())
 
315
 
242
316
    def test_returns_empty_list_when_all_clusters_fail(self):
243
317
        factory.make_NodeGroup().accept()
244
318
        factory.make_NodeGroup().accept()