@@ -11478,13 +11478,61 @@ def fake_volume_get(self, context, volume_id, microversion=None):
11478
11478
mock_detach.assert_called_once_with(mock.ANY, uuids.volume,
11479
11479
instance.uuid, None)
11480
11480
11481
+ @mock.patch.object(context.RequestContext, 'elevated')
11482
+ @mock.patch.object(cinder.API, 'detach')
11483
+ @mock.patch.object(cinder.API, 'terminate_connection')
11484
+ @mock.patch.object(compute_manager.ComputeManager,
11485
+ '_get_instance_block_device_info')
11486
+ @mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
11487
+ def test_shutdown_with_legacy_volume_detach(
11488
+ self, mock_get_connector, mock_info, mock_terminate, mock_detach,
11489
+ mock_elevated,
11490
+ ):
11491
+ # test _shutdown_instance with legacy BDMs without a volume
11492
+ # attachment ID
11493
+ admin = context.get_admin_context()
11494
+ mock_elevated.return_value = admin
11495
+ instance = self._create_fake_instance_obj()
11496
+ connector = 'fake-connector'
11497
+ mock_get_connector.return_value = connector
11498
+
11499
+ vol_a_bdm = block_device_obj.BlockDeviceMapping(
11500
+ instance_uuid=instance['uuid'],
11501
+ source_type='volume', destination_type='volume',
11502
+ delete_on_termination=False,
11503
+ volume_id=uuids.volume_a_id,
11504
+ attachment_id=None)
11505
+ vol_b_bdm = block_device_obj.BlockDeviceMapping(
11506
+ instance_uuid=instance['uuid'],
11507
+ source_type='volume', destination_type='volume',
11508
+ delete_on_termination=False,
11509
+ volume_id=uuids.volume_b_id,
11510
+ attachment_id=None)
11511
+ bdms = [vol_a_bdm, vol_b_bdm]
11512
+
11513
+ self.compute._shutdown_instance(admin, instance, bdms)
11514
+
11515
+ # we should only got the connector once, regardless of the number of
11516
+ # volumes
11517
+ mock_get_connector.assert_called_once_with(instance)
11518
+ # but we should have separate terminate and detach calls
11519
+ mock_terminate.assert_has_calls([
11520
+ mock.call(admin, uuids.volume_a_id, connector),
11521
+ mock.call(admin, uuids.volume_b_id, connector),
11522
+ ])
11523
+ mock_detach.assert_has_calls([
11524
+ mock.call(admin, uuids.volume_a_id, instance.uuid),
11525
+ mock.call(admin, uuids.volume_b_id, instance.uuid),
11526
+ ])
11527
+
11481
11528
@mock.patch.object(context.RequestContext, 'elevated')
11482
11529
@mock.patch.object(cinder.API, 'attachment_delete')
11483
11530
@mock.patch.object(compute_manager.ComputeManager,
11484
11531
'_get_instance_block_device_info')
11485
- def test_shutdown_with_attachment_delete(self, mock_info,
11486
- mock_attach_delete,
11487
- mock_elevated):
11532
+ @mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
11533
+ def test_shutdown_with_attachment_delete(
11534
+ self, mock_get_connector, mock_info, mock_attach_delete, mock_elevated,
11535
+ ):
11488
11536
# test _shutdown_instance with volume bdm containing an
11489
11537
# attachment id. This should use the v3 cinder api.
11490
11538
admin = context.get_admin_context()
@@ -11504,14 +11552,18 @@ def test_shutdown_with_attachment_delete(self, mock_info,
11504
11552
self.compute._shutdown_instance(admin, instance, bdms)
11505
11553
11506
11554
mock_attach_delete.assert_called_once_with(admin, attachment_id)
11555
+ # we shouldn't try to get a connector for a cinder v3-style attachment
11556
+ mock_get_connector.assert_not_called()
11507
11557
11508
11558
@mock.patch.object(compute_manager.LOG, 'debug')
11509
11559
@mock.patch.object(cinder.API, 'attachment_delete')
11510
11560
@mock.patch.object(compute_manager.ComputeManager,
11511
11561
'_get_instance_block_device_info')
11512
- def test_shutdown_with_attachment_not_found(self, mock_info,
11513
- mock_attach_delete,
11514
- mock_debug_log):
11562
+ @mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
11563
+ def test_shutdown_with_attachment_not_found(
11564
+ self, mock_get_connector, mock_info, mock_attach_delete,
11565
+ mock_debug_log,
11566
+ ):
11515
11567
# test _shutdown_instance with attachment_delete throwing
11516
11568
# a VolumeAttachmentNotFound exception. This should not
11517
11569
# cause _shutdown_instance to fail. Only a debug log
@@ -11537,6 +11589,8 @@ def test_shutdown_with_attachment_not_found(self, mock_info,
11537
11589
# get last call to LOG.debug and verify correct exception is in there
11538
11590
self.assertIsInstance(mock_debug_log.call_args[0][1],
11539
11591
exception.VolumeAttachmentNotFound)
11592
+ # we shouldn't try to get a connector for a cinder v3-style attachment
11593
+ mock_get_connector.assert_not_called()
11540
11594
11541
11595
def test_terminate_with_volumes(self):
11542
11596
# Make sure that volumes get detached during instance termination.
0 commit comments