@@ -11114,6 +11114,153 @@ def test_delete_volume_attachments_errors(self):
11114
11114
self.assertIn('Failed to delete volume attachment with ID %s' %
11115
11115
uuids.attachment1, self.stdlog.logger.output)
11116
11116
11117
+ @mock.patch('nova.compute.utils.notify_usage_exists')
11118
+ @mock.patch('nova.objects.Instance.save')
11119
+ @mock.patch('nova.compute.utils.add_instance_fault_from_exc')
11120
+ @mock.patch('nova.compute.manager.InstanceEvents.'
11121
+ 'clear_events_for_instance')
11122
+ def test_revert_snapshot_based_resize_at_dest_error_handling(
11123
+ self, mock_clear_events, mock_add_fault, mock_inst_save,
11124
+ mock_notify_usage):
11125
+ """Tests error handling in revert_snapshot_based_resize_at_dest when
11126
+ a failure occurs.
11127
+ """
11128
+ self.instance.task_state = task_states.RESIZE_REVERTING
11129
+ error = test.TestingException('oops')
11130
+ with mock.patch.object(
11131
+ self.compute, '_revert_snapshot_based_resize_at_dest',
11132
+ side_effect=error) as mock_revert:
11133
+ self.assertRaises(
11134
+ test.TestingException,
11135
+ self.compute.revert_snapshot_based_resize_at_dest,
11136
+ self.context, self.instance, self.migration)
11137
+ mock_notify_usage.assert_called_once_with(
11138
+ self.compute.notifier, self.context, self.instance,
11139
+ self.compute.host, current_period=True)
11140
+ mock_revert.assert_called_once_with(
11141
+ self.context, self.instance, self.migration)
11142
+ mock_inst_save.assert_called()
11143
+ # _error_out_instance_on_exception sets the instance to ERROR.
11144
+ self.assertEqual(vm_states.ERROR, self.instance.vm_state)
11145
+ # reverts_task_state will reset the task_state to None.
11146
+ self.assertIsNone(self.instance.task_state)
11147
+ # Ensure wrap_instance_fault was called.
11148
+ mock_add_fault.assert_called_once_with(
11149
+ self.context, self.instance, error, test.MatchType(tuple))
11150
+ # errors_out_migration should mark the migration as 'error' status
11151
+ self.assertEqual('error', self.migration.status)
11152
+ self.migration.save.assert_called_once_with()
11153
+ # Assert wrap_exception is called.
11154
+ self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS))
11155
+ self.assertEqual(
11156
+ 'compute.%s' % fields.NotificationAction.EXCEPTION,
11157
+ fake_notifier.VERSIONED_NOTIFICATIONS[0]['event_type'])
11158
+ # clear_events_for_instance should not have been called.
11159
+ mock_clear_events.assert_not_called()
11160
+
11161
+ @mock.patch('nova.compute.utils.notify_usage_exists', new=mock.Mock())
11162
+ @mock.patch('nova.compute.manager.ComputeManager.'
11163
+ '_revert_snapshot_based_resize_at_dest')
11164
+ def test_revert_snapshot_based_resize_at_dest_post_error_log(self, revert):
11165
+ """Tests when _revert_snapshot_based_resize_at_dest is OK but
11166
+ post-processing cleanup fails and is just logged.
11167
+ """
11168
+ # First test _delete_scheduler_instance_info failing.
11169
+ with mock.patch.object(
11170
+ self.compute, '_delete_scheduler_instance_info',
11171
+ side_effect=(
11172
+ test.TestingException('scheduler'), None)) as mock_del:
11173
+ self.compute.revert_snapshot_based_resize_at_dest(
11174
+ self.context, self.instance, self.migration)
11175
+ revert.assert_called_once()
11176
+ mock_del.assert_called_once_with(self.context, self.instance.uuid)
11177
+ self.assertIn('revert_snapshot_based_resize_at_dest failed during '
11178
+ 'post-processing. Error: scheduler',
11179
+ self.stdlog.logger.output)
11180
+ revert.reset_mock()
11181
+ mock_del.reset_mock()
11182
+
11183
+ # Now test clear_events_for_instance failing.
11184
+ with mock.patch.object(
11185
+ self.compute.instance_events, 'clear_events_for_instance',
11186
+ side_effect=test.TestingException(
11187
+ 'events')) as mock_events:
11188
+ self.compute.revert_snapshot_based_resize_at_dest(
11189
+ self.context, self.instance, self.migration)
11190
+ revert.assert_called_once()
11191
+ mock_del.assert_called_once_with(self.context, self.instance.uuid)
11192
+ mock_events.assert_called_once_with(self.instance)
11193
+ self.assertIn('revert_snapshot_based_resize_at_dest failed during '
11194
+ 'post-processing. Error: events',
11195
+ self.stdlog.logger.output)
11196
+ # Assert _error_out_instance_on_exception wasn't tripped somehow.
11197
+ self.assertNotEqual(vm_states.ERROR, self.instance.vm_state)
11198
+
11199
+ @mock.patch('nova.objects.Instance.save')
11200
+ @mock.patch('nova.objects.Instance.revert_migration_context')
11201
+ @mock.patch('nova.objects.BlockDeviceMappingList.get_by_instance_uuid')
11202
+ def test_revert_snapshot_based_resize_at_dest(
11203
+ self, mock_get_bdms, mock_revert_mig_ctxt, mock_inst_save):
11204
+ """Happy path test for _revert_snapshot_based_resize_at_dest"""
11205
+ # Setup more mocks.
11206
+ def stub_migrate_instance_start(ctxt, instance, migration):
11207
+ # The migration.dest_compute should have been mutated to point
11208
+ # at the source compute.
11209
+ self.assertEqual(migration.source_compute, migration.dest_compute)
11210
+
11211
+ def stub_setup_networks_on_host(ctxt, instance, *args, **kwargs):
11212
+ # The instance.host should have been mutated to point at the
11213
+ # source compute.
11214
+ self.assertEqual(self.migration.source_compute, instance.host)
11215
+ # Raise PortBindingDeletionFailed to make sure it's caught and
11216
+ # logged but not fatal.
11217
+ raise exception.PortBindingDeletionFailed(port_id=uuids.port_id,
11218
+ host=self.compute.host)
11219
+
11220
+ with test.nested(
11221
+ mock.patch.object(self.compute, 'network_api'),
11222
+ mock.patch.object(self.compute, '_get_instance_block_device_info'),
11223
+ mock.patch.object(self.compute.driver, 'destroy'),
11224
+ mock.patch.object(self.compute, '_delete_volume_attachments'),
11225
+ mock.patch.object(self.compute.rt, 'drop_move_claim')
11226
+ ) as (
11227
+ mock_network_api, mock_get_bdi, mock_destroy,
11228
+ mock_delete_attachments, mock_drop_claim
11229
+ ):
11230
+ mock_network_api.migrate_instance_start.side_effect = \
11231
+ stub_migrate_instance_start
11232
+ mock_network_api.setup_networks_on_host.side_effect = \
11233
+ stub_setup_networks_on_host
11234
+ # Run the code.
11235
+ self.compute._revert_snapshot_based_resize_at_dest(
11236
+ self.context, self.instance, self.migration)
11237
+ # Assert the calls.
11238
+ mock_network_api.get_instance_nw_info.assert_called_once_with(
11239
+ self.context, self.instance)
11240
+ mock_get_bdi.assert_called_once_with(
11241
+ self.context, self.instance, bdms=mock_get_bdms.return_value)
11242
+ mock_destroy.assert_called_once_with(
11243
+ self.context, self.instance,
11244
+ mock_network_api.get_instance_nw_info.return_value,
11245
+ block_device_info=mock_get_bdi.return_value)
11246
+ mock_network_api.migrate_instance_start.assert_called_once_with(
11247
+ self.context, self.instance, self.migration)
11248
+ mock_network_api.setup_networks_on_host.assert_called_once_with(
11249
+ self.context, self.instance, host=self.compute.host,
11250
+ teardown=True)
11251
+ # Assert that even though setup_networks_on_host raised
11252
+ # PortBindingDeletionFailed it was handled and logged.
11253
+ self.assertIn('Failed to delete port bindings from target host.',
11254
+ self.stdlog.logger.output)
11255
+ mock_delete_attachments.assert_called_once_with(
11256
+ self.context, mock_get_bdms.return_value)
11257
+ mock_revert_mig_ctxt.assert_called_once_with()
11258
+ mock_inst_save.assert_called_once_with(
11259
+ expected_task_state=task_states.RESIZE_REVERTING)
11260
+ mock_drop_claim.assert_called_once_with(
11261
+ self.context, self.instance, self.instance.node,
11262
+ instance_type=self.instance.new_flavor)
11263
+
11117
11264
11118
11265
class ComputeManagerInstanceUsageAuditTestCase(test.TestCase):
11119
11266
def setUp(self):
0 commit comments