@@ -11559,13 +11559,61 @@ def fake_volume_get(self, context, volume_id, microversion=None):
11559
11559
mock_detach.assert_called_once_with(mock.ANY, uuids.volume,
11560
11560
instance.uuid, None)
11561
11561
11562
+ @mock.patch.object(context.RequestContext, 'elevated')
11563
+ @mock.patch.object(cinder.API, 'detach')
11564
+ @mock.patch.object(cinder.API, 'terminate_connection')
11565
+ @mock.patch.object(compute_manager.ComputeManager,
11566
+ '_get_instance_block_device_info')
11567
+ @mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
11568
+ def test_shutdown_with_legacy_volume_detach(
11569
+ self, mock_get_connector, mock_info, mock_terminate, mock_detach,
11570
+ mock_elevated,
11571
+ ):
11572
+ # test _shutdown_instance with legacy BDMs without a volume
11573
+ # attachment ID
11574
+ admin = context.get_admin_context()
11575
+ mock_elevated.return_value = admin
11576
+ instance = self._create_fake_instance_obj()
11577
+ connector = 'fake-connector'
11578
+ mock_get_connector.return_value = connector
11579
+
11580
+ vol_a_bdm = block_device_obj.BlockDeviceMapping(
11581
+ instance_uuid=instance['uuid'],
11582
+ source_type='volume', destination_type='volume',
11583
+ delete_on_termination=False,
11584
+ volume_id=uuids.volume_a_id,
11585
+ attachment_id=None)
11586
+ vol_b_bdm = block_device_obj.BlockDeviceMapping(
11587
+ instance_uuid=instance['uuid'],
11588
+ source_type='volume', destination_type='volume',
11589
+ delete_on_termination=False,
11590
+ volume_id=uuids.volume_b_id,
11591
+ attachment_id=None)
11592
+ bdms = [vol_a_bdm, vol_b_bdm]
11593
+
11594
+ self.compute._shutdown_instance(admin, instance, bdms)
11595
+
11596
+ # we should only got the connector once, regardless of the number of
11597
+ # volumes
11598
+ mock_get_connector.assert_called_once_with(instance)
11599
+ # but we should have separate terminate and detach calls
11600
+ mock_terminate.assert_has_calls([
11601
+ mock.call(admin, uuids.volume_a_id, connector),
11602
+ mock.call(admin, uuids.volume_b_id, connector),
11603
+ ])
11604
+ mock_detach.assert_has_calls([
11605
+ mock.call(admin, uuids.volume_a_id, instance.uuid),
11606
+ mock.call(admin, uuids.volume_b_id, instance.uuid),
11607
+ ])
11608
+
11562
11609
@mock.patch.object(context.RequestContext, 'elevated')
11563
11610
@mock.patch.object(cinder.API, 'attachment_delete')
11564
11611
@mock.patch.object(compute_manager.ComputeManager,
11565
11612
'_get_instance_block_device_info')
11566
- def test_shutdown_with_attachment_delete(self, mock_info,
11567
- mock_attach_delete,
11568
- mock_elevated):
11613
+ @mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
11614
+ def test_shutdown_with_attachment_delete(
11615
+ self, mock_get_connector, mock_info, mock_attach_delete, mock_elevated,
11616
+ ):
11569
11617
# test _shutdown_instance with volume bdm containing an
11570
11618
# attachment id. This should use the v3 cinder api.
11571
11619
admin = context.get_admin_context()
@@ -11585,14 +11633,18 @@ def test_shutdown_with_attachment_delete(self, mock_info,
11585
11633
self.compute._shutdown_instance(admin, instance, bdms)
11586
11634
11587
11635
mock_attach_delete.assert_called_once_with(admin, attachment_id)
11636
+ # we shouldn't try to get a connector for a cinder v3-style attachment
11637
+ mock_get_connector.assert_not_called()
11588
11638
11589
11639
@mock.patch.object(compute_manager.LOG, 'debug')
11590
11640
@mock.patch.object(cinder.API, 'attachment_delete')
11591
11641
@mock.patch.object(compute_manager.ComputeManager,
11592
11642
'_get_instance_block_device_info')
11593
- def test_shutdown_with_attachment_not_found(self, mock_info,
11594
- mock_attach_delete,
11595
- mock_debug_log):
11643
+ @mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
11644
+ def test_shutdown_with_attachment_not_found(
11645
+ self, mock_get_connector, mock_info, mock_attach_delete,
11646
+ mock_debug_log,
11647
+ ):
11596
11648
# test _shutdown_instance with attachment_delete throwing
11597
11649
# a VolumeAttachmentNotFound exception. This should not
11598
11650
# cause _shutdown_instance to fail. Only a debug log
@@ -11618,6 +11670,8 @@ def test_shutdown_with_attachment_not_found(self, mock_info,
11618
11670
# get last call to LOG.debug and verify correct exception is in there
11619
11671
self.assertIsInstance(mock_debug_log.call_args[0][1],
11620
11672
exception.VolumeAttachmentNotFound)
11673
+ # we shouldn't try to get a connector for a cinder v3-style attachment
11674
+ mock_get_connector.assert_not_called()
11621
11675
11622
11676
def test_terminate_with_volumes(self):
11623
11677
# Make sure that volumes get detached during instance termination.
0 commit comments