Execute TargetDBSetupTask
This adds the code to CrossCellMigrationTask which executes the TargetDBSetupTask sub-task and stores some fields on the main task for use later when dealing with the target cell. Part of blueprint cross-cell-resize Change-Id: I00683acee216c0c0ad87be3eb5ec832f20f054c7
This commit is contained in:
@@ -11,10 +11,12 @@
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import copy
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.conductor.tasks import base
|
||||
from nova import context as nova_context
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import network
|
||||
@@ -226,6 +228,9 @@ class CrossCellMigrationTask(base.TaskBase):
|
||||
self.host_selection = host_selection
|
||||
self.alternate_hosts = alternate_hosts
|
||||
|
||||
self._target_cell_instance = None
|
||||
self._target_cell_context = None
|
||||
|
||||
self.network_api = network.API()
|
||||
self.volume_api = cinder.API()
|
||||
|
||||
@@ -233,6 +238,41 @@ class CrossCellMigrationTask(base.TaskBase):
|
||||
# rollback routines if something fails.
|
||||
self._completed_tasks = collections.OrderedDict()
|
||||
|
||||
def _get_target_cell_mapping(self):
|
||||
"""Get the target host CellMapping for the selected host
|
||||
|
||||
:returns: nova.objects.CellMapping for the cell of the selected target
|
||||
host
|
||||
:raises: nova.exception.CellMappingNotFound if the cell mapping for
|
||||
the selected target host cannot be found (this should not happen
|
||||
if the scheduler just selected it)
|
||||
"""
|
||||
return objects.CellMapping.get_by_uuid(
|
||||
self.context, self.host_selection.cell_uuid)
|
||||
|
||||
def _setup_target_cell_db(self):
|
||||
"""Creates the instance and its related records in the target cell
|
||||
|
||||
Upon successful completion the self._target_cell_context and
|
||||
self._target_cell_instance variables are set.
|
||||
|
||||
:returns: The active Migration object from the target cell DB.
|
||||
"""
|
||||
LOG.debug('Setting up the target cell database for the instance and '
|
||||
'its related records.', instance=self.instance)
|
||||
target_cell_mapping = self._get_target_cell_mapping()
|
||||
# Clone the context targeted at the source cell and then target the
|
||||
# clone at the target cell.
|
||||
self._target_cell_context = copy.copy(self.context)
|
||||
nova_context.set_target_cell(
|
||||
self._target_cell_context, target_cell_mapping)
|
||||
task = TargetDBSetupTask(
|
||||
self.context, self.instance, self.migration,
|
||||
self._target_cell_context)
|
||||
self._target_cell_instance, target_cell_migration = task.execute()
|
||||
self._completed_tasks['TargetDBSetupTask'] = task
|
||||
return target_cell_migration
|
||||
|
||||
def _perform_external_api_checks(self):
|
||||
"""Performs checks on external service APIs for support.
|
||||
|
||||
@@ -268,6 +308,15 @@ class CrossCellMigrationTask(base.TaskBase):
|
||||
# Make sure neutron and cinder APIs we need are available.
|
||||
self._perform_external_api_checks()
|
||||
|
||||
# Before preparing the target host create the instance record data
|
||||
# in the target cell database since we cannot do anything in the
|
||||
# target cell without having an instance record there. Remember that
|
||||
# we lose the cell-targeting on the request context over RPC so we
|
||||
# cannot simply pass the source cell context and instance over RPC
|
||||
# to the target compute host and assume changes get mirrored back to
|
||||
# the source cell database.
|
||||
self._setup_target_cell_db()
|
||||
|
||||
def rollback(self):
|
||||
"""Rollback based on how sub-tasks completed
|
||||
|
||||
|
||||
@@ -392,8 +392,10 @@ class CrossCellMigrationTaskTestCase(test.NoDBTestCase):
|
||||
with test.nested(
|
||||
mock.patch.object(self.task.migration, 'save'),
|
||||
mock.patch.object(self.task, '_perform_external_api_checks'),
|
||||
mock.patch.object(self.task, '_setup_target_cell_db'),
|
||||
) as (
|
||||
mock_migration_save, mock_perform_external_api_checks,
|
||||
mock_setup_target_cell_db,
|
||||
):
|
||||
self.task.execute()
|
||||
# Assert the calls
|
||||
@@ -401,6 +403,7 @@ class CrossCellMigrationTaskTestCase(test.NoDBTestCase):
|
||||
'Migration.cross_cell_move should be True.')
|
||||
mock_migration_save.assert_called_once_with()
|
||||
mock_perform_external_api_checks.assert_called_once_with()
|
||||
mock_setup_target_cell_db.assert_called_once_with()
|
||||
# Now rollback the completed sub-tasks
|
||||
self.task.rollback()
|
||||
|
||||
@@ -467,3 +470,36 @@ class CrossCellMigrationTaskTestCase(test.NoDBTestCase):
|
||||
# The 2nd task rollback should have raised and been logged.
|
||||
mock_log_exception.assert_called_once()
|
||||
self.assertEqual('1', mock_log_exception.call_args[0][1])
|
||||
|
||||
@mock.patch('nova.objects.CellMapping.get_by_uuid')
|
||||
@mock.patch('nova.context.set_target_cell')
|
||||
@mock.patch.object(cross_cell_migrate.TargetDBSetupTask, 'execute')
|
||||
def test_setup_target_cell_db(self, mock_target_db_set_task_execute,
|
||||
mock_set_target_cell, mock_get_cell_mapping):
|
||||
"""Tests setting up and executing TargetDBSetupTask"""
|
||||
mock_target_db_set_task_execute.return_value = (
|
||||
mock.sentinel.target_cell_instance,
|
||||
mock.sentinel.target_cell_migration)
|
||||
result = self.task._setup_target_cell_db()
|
||||
mock_target_db_set_task_execute.assert_called_once_with()
|
||||
mock_get_cell_mapping.assert_called_once_with(
|
||||
self.task.context, self.task.host_selection.cell_uuid)
|
||||
# The target_cell_context should be set on the main task but as a copy
|
||||
# of the source context.
|
||||
self.assertIsNotNone(self.task._target_cell_context)
|
||||
self.assertIsNot(self.task._target_cell_context, self.task.context)
|
||||
# The target cell context should have been targeted to the target
|
||||
# cell mapping.
|
||||
mock_set_target_cell.assert_called_once_with(
|
||||
self.task._target_cell_context, mock_get_cell_mapping.return_value)
|
||||
# The resulting migration record from TargetDBSetupTask should have
|
||||
# been returned.
|
||||
self.assertIs(result, mock.sentinel.target_cell_migration)
|
||||
# The target_cell_instance should be set on the main task.
|
||||
self.assertIsNotNone(self.task._target_cell_instance)
|
||||
self.assertIs(self.task._target_cell_instance,
|
||||
mock.sentinel.target_cell_instance)
|
||||
# And the completed task should have been recorded for rollbacks.
|
||||
self.assertIn('TargetDBSetupTask', self.task._completed_tasks)
|
||||
self.assertIsInstance(self.task._completed_tasks['TargetDBSetupTask'],
|
||||
cross_cell_migrate.TargetDBSetupTask)
|
||||
|
||||
Reference in New Issue
Block a user