|
|
@@ -0,0 +1,2038 @@
|
|
|
+# Copyright 2024 Cloudbase Solutions Srl
|
|
|
+# All Rights Reserved.
|
|
|
+
|
|
|
+from unittest import mock
|
|
|
+
|
|
|
+from taskflow.types import failure
|
|
|
+
|
|
|
+from coriolis.conductor.rpc.client import ConductorClient
|
|
|
+from coriolis import exception
|
|
|
+from coriolis.minion_manager.rpc.client import MinionManagerClient
|
|
|
+from coriolis.minion_manager.rpc import tasks
|
|
|
+from coriolis.taskflow import base
|
|
|
+from coriolis.tests import test_base
|
|
|
+
|
|
|
+
|
|
|
+class CoriolisTestException(Exception):
|
|
|
+ pass
|
|
|
+
|
|
|
+
|
|
|
+class MinionManagerTaskEventMixinTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis MinionManagerTaskEventMixin class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(MinionManagerTaskEventMixinTestCase, self).setUp()
|
|
|
+ self.task = tasks.MinionManagerTaskEventMixin()
|
|
|
+ self.task._minion_pool_id = mock.sentinel.minion_pool_id
|
|
|
+
|
|
|
+ def test__conductor_client(self):
|
|
|
+ with mock.patch(
|
|
|
+ 'coriolis.conductor.rpc.client.ConductorClient',
|
|
|
+ return_value=mock.MagicMock(spec=ConductorClient)) as \
|
|
|
+ mock_Conductor_client:
|
|
|
+ result = self.task._conductor_client
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result, mock_Conductor_client.return_value
|
|
|
+ )
|
|
|
+ mock_Conductor_client.assert_called_once_with()
|
|
|
+
|
|
|
+ def test__conductor_client_already_set(self):
|
|
|
+ with mock.patch(
|
|
|
+ 'coriolis.conductor.rpc.client.ConductorClient') as \
|
|
|
+ mock_Conductor_client:
|
|
|
+ self.task._conductor_client_instance = mock.MagicMock(
|
|
|
+ spec=ConductorClient)
|
|
|
+
|
|
|
+ result = self.task._conductor_client
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result, self.task._conductor_client_instance
|
|
|
+ )
|
|
|
+ mock_Conductor_client.assert_not_called()
|
|
|
+
|
|
|
+ def test__minion_manager_client(self):
|
|
|
+ with mock.patch(
|
|
|
+ 'coriolis.minion_manager.rpc.client.MinionManagerClient',
|
|
|
+ return_value=mock.MagicMock(spec=MinionManagerClient)) as \
|
|
|
+ mock_Minion_Manager_Client:
|
|
|
+ result = self.task._minion_manager_client
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result, mock_Minion_Manager_Client.return_value
|
|
|
+ )
|
|
|
+ mock_Minion_Manager_Client.assert_called_once_with()
|
|
|
+
|
|
|
+ def test__minion_manager_client_already_set(self):
|
|
|
+ with mock.patch(
|
|
|
+ 'coriolis.minion_manager.rpc.client.MinionManagerClient') as \
|
|
|
+ mock_Minion_Manager_Client:
|
|
|
+ self.task._minion_manager_client_instance = mock.MagicMock(
|
|
|
+ spec=MinionManagerClient)
|
|
|
+
|
|
|
+ result = self.task._minion_manager_client
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result, self.task._minion_manager_client_instance
|
|
|
+ )
|
|
|
+ mock_Minion_Manager_Client.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'add_minion_pool_event')
|
|
|
+ def test__add_minion_pool_event(self, mock_add_minion_pool_event):
|
|
|
+ result = self.task._add_minion_pool_event(
|
|
|
+ mock.sentinel.context, mock.sentinel.message,
|
|
|
+ level=tasks.constants.TASK_EVENT_INFO)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_add_minion_pool_event.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ tasks.constants.TASK_EVENT_INFO, mock.sentinel.message
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ def test__get_minion_machine(self, mock_get_minion_machine):
|
|
|
+ result = self.task._get_minion_machine(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_machine_id)
|
|
|
+ self.assertEqual(result, mock_get_minion_machine.return_value)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_machine_id)
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ def test__get_minion_machine_not_found(self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = None
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ tasks.exception.NotFound, self.task._get_minion_machine,
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'set_minion_pool_status')
|
|
|
+ def test__set_minion_pool_status(self, mock_set_minion_pool_status):
|
|
|
+ with mock.patch.object(
|
|
|
+ tasks.minion_manager_utils, 'get_minion_pool_lock') as \
|
|
|
+ mock_get_minion_pool_lock:
|
|
|
+ result = self.task._set_minion_pool_status(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ mock.sentinel.new_status)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ mock.sentinel.minion_pool_id, external=True)
|
|
|
+
|
|
|
+ mock_set_minion_pool_status.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ mock.sentinel.new_status)
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_machine')
|
|
|
+ def test__update_minion_machine(self, mock_update_minion_machine):
|
|
|
+ with mock.patch.object(
|
|
|
+ tasks.minion_manager_utils, 'get_minion_pool_lock') as \
|
|
|
+ mock_get_minion_pool_lock:
|
|
|
+ result = self.task._update_minion_machine(
|
|
|
+ mock.sentinel.ctxt, mock.sentinel.minion_pool_id,
|
|
|
+ mock.sentinel.minion_machine_id, mock.sentinel.updated_values)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ mock.sentinel.minion_pool_id, external=True)
|
|
|
+
|
|
|
+ mock_update_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.ctxt, mock.sentinel.minion_machine_id,
|
|
|
+ mock.sentinel.updated_values)
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'set_minion_machine_allocation_status')
|
|
|
+ def test__set_minion_machine_allocation_status(
|
|
|
+ self, mock_set_minion_machine_allocation_status):
|
|
|
+ with mock.patch.object(
|
|
|
+ tasks.minion_manager_utils, 'get_minion_pool_lock') as \
|
|
|
+ mock_get_minion_pool_lock:
|
|
|
+ result = self.task._set_minion_machine_allocation_status(
|
|
|
+ mock.sentinel.ctxt, mock.sentinel.minion_pool_id,
|
|
|
+ mock.sentinel.minion_machine_id, mock.sentinel.new_status)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ mock.sentinel.minion_pool_id, external=True)
|
|
|
+
|
|
|
+ mock_set_minion_machine_allocation_status.assert_called_once_with(
|
|
|
+ mock.sentinel.ctxt, mock.sentinel.minion_machine_id,
|
|
|
+ mock.sentinel.new_status)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_update_minion_machine'
|
|
|
+ )
|
|
|
+ def test__set_minion_machine_power_status(
|
|
|
+ self, mock_update_minion_machine):
|
|
|
+ result = self.task._set_minion_machine_power_status(
|
|
|
+ mock.sentinel.ctxt, mock.sentinel.minion_pool_id,
|
|
|
+ mock.sentinel.minion_machine_id, mock.sentinel.new_status)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_update_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.ctxt, mock.sentinel.minion_pool_id,
|
|
|
+ mock.sentinel.minion_machine_id,
|
|
|
+ {'power_status': mock.sentinel.new_status}
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+class BaseReportMinionAllocationFailureForActionTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseReportMinionAllocationFailureForActionTask,
|
|
|
+ '__abstractmethods__', set()
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseReportMinionAllocationFailureForActionTask, '_get_task_name'
|
|
|
+ )
|
|
|
+ def setUp(self, mock_get_task_name):
|
|
|
+ super(
|
|
|
+ BaseReportMinionAllocationFailureForActionTaskTestCase,
|
|
|
+ self).setUp()
|
|
|
+ self.task = tasks._BaseReportMinionAllocationFailureForActionTask(
|
|
|
+ mock.sentinel.action_id)
|
|
|
+
|
|
|
+ def test_execute(self):
|
|
|
+ result = self.task.execute(mock.sentinel.context)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseReportMinionAllocationFailureForActionTask,
|
|
|
+ '_report_machine_allocation_failure'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ MinionManagerClient, 'deallocate_minion_machines_for_action'
|
|
|
+ )
|
|
|
+ def test_revert(self, mock_deallocate_minion_machines_for_action,
|
|
|
+ mock_report_machine_allocation_failure):
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.flow_failures)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_deallocate_minion_machines_for_action.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.action_id)
|
|
|
+ mock_report_machine_allocation_failure.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.action_id,
|
|
|
+ "No flow failures provided.")
|
|
|
+
|
|
|
+
|
|
|
+class ReportMinionAllocationFailureForMigrationTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+ def setUp(self):
|
|
|
+ super(ReportMinionAllocationFailureForMigrationTaskTestCase,
|
|
|
+ self).setUp()
|
|
|
+ self.action_id = mock.sentinel.action_id
|
|
|
+ self.task = tasks.ReportMinionAllocationFailureForMigrationTask(
|
|
|
+ self.action_id)
|
|
|
+
|
|
|
+ def test_get_task_name(self):
|
|
|
+ result = self.task._get_task_name(self.action_id)
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ f"migration-{self.action_id}-minion-allocation-failure"
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ ConductorClient, 'report_migration_minions_allocation_error'
|
|
|
+ )
|
|
|
+ def test__report_machine_allocation_failure(
|
|
|
+ self, mock_report_migration_minions_allocation_error):
|
|
|
+ result = self.task._report_machine_allocation_failure(
|
|
|
+ mock.sentinel.context, self.action_id, mock.sentinel.failure_str)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_report_migration_minions_allocation_error.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.action_id, mock.sentinel.failure_str
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+class ReportMinionAllocationFailureForReplicaTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+ def setUp(self):
|
|
|
+ super(ReportMinionAllocationFailureForReplicaTaskTestCase,
|
|
|
+ self).setUp()
|
|
|
+ self.action_id = mock.sentinel.action_id
|
|
|
+ self.task = tasks.ReportMinionAllocationFailureForReplicaTask(
|
|
|
+ self.action_id)
|
|
|
+
|
|
|
+ def test_get_task_name(self):
|
|
|
+ result = self.task._get_task_name(self.action_id)
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ f"replica-{self.action_id}-minion-allocation-failure"
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ ConductorClient, 'report_replica_minions_allocation_error'
|
|
|
+ )
|
|
|
+ def test__report_machine_allocation_failure(
|
|
|
+ self, mock_report_replica_minions_allocation_error):
|
|
|
+ result = self.task._report_machine_allocation_failure(
|
|
|
+ mock.sentinel.context, self.action_id, mock.sentinel.failure_str)
|
|
|
+
|
|
|
+ self.assertIsNone(result)
|
|
|
+ mock_report_replica_minions_allocation_error.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.action_id, mock.sentinel.failure_str
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+class BaseConfirmMinionAllocationForActionTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask,
|
|
|
+ '__abstractmethods__', set()
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask, '_get_task_name'
|
|
|
+ )
|
|
|
+ def setUp(self, mock_get_task_name):
|
|
|
+ super(BaseConfirmMinionAllocationForActionTaskTestCase, self).setUp()
|
|
|
+ self.minion_machine = mock.MagicMock()
|
|
|
+ self.minion_machine.id = mock.sentinel.minion_machine_id
|
|
|
+ self.minion_machine.pool_id = mock.sentinel.pool_id
|
|
|
+ self.minion_machine.allocated_action = mock.sentinel.action_id
|
|
|
+ self.minion_machine.allocation_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_IN_USE)
|
|
|
+ self.minion_machine.power_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_ON)
|
|
|
+
|
|
|
+ self.allocated_machine_id_mappings = {
|
|
|
+ mock.sentinel.instance_id: {
|
|
|
+ 'origin_minion_id': mock.sentinel.origin_minion_id,
|
|
|
+ 'destination_minion_id': mock.sentinel.destination_minion_id,
|
|
|
+ 'osmorphing_minion_id': mock.sentinel.osmorphing_minion_id,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.task = tasks._BaseConfirmMinionAllocationForActionTask(
|
|
|
+ mock.sentinel.action_id, self.allocated_machine_id_mappings)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask,
|
|
|
+ '_confirm_machine_allocation_for_action'
|
|
|
+ )
|
|
|
+ def test_execute(self, mock_confirm_allocation, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ result = self.task.execute(mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_has_calls([
|
|
|
+ mock.call(mock.sentinel.context, mock.sentinel.origin_minion_id,
|
|
|
+ raise_if_not_found=True),
|
|
|
+ mock.call(mock.sentinel.context,
|
|
|
+ mock.sentinel.destination_minion_id,
|
|
|
+ raise_if_not_found=True),
|
|
|
+ mock.call(mock.sentinel.context,
|
|
|
+ mock.sentinel.osmorphing_minion_id,
|
|
|
+ raise_if_not_found=True)], any_order=True)
|
|
|
+
|
|
|
+ expected_machine_allocations = {
|
|
|
+ mock.sentinel.instance_id: {
|
|
|
+ 'origin_minion': self.minion_machine.to_dict(),
|
|
|
+ 'destination_minion': self.minion_machine.to_dict(),
|
|
|
+ 'osmorphing_minion': self.minion_machine.to_dict(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mock_confirm_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.action_id,
|
|
|
+ expected_machine_allocations
|
|
|
+ )
|
|
|
+
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_raises_exception_when_allocation_status_is_not_in_use(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.allocation_status = 'DEALLOCATED'
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState,
|
|
|
+ self.task.execute, mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin_minion_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_raises_exception_when_allocated_action_is_not_correct(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.allocated_action = 'ANOTHER_ACTION'
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState,
|
|
|
+ self.task.execute, mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin_minion_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_raises_exception_when_power_status_is_not_powered_on(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.power_status = 'POWERED_OFF'
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState,
|
|
|
+ self.task.execute, mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin_minion_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask,
|
|
|
+ '_confirm_machine_allocation_for_action'
|
|
|
+ )
|
|
|
+ def test_execute_no_machine_allocation(
|
|
|
+ self, mock_confirm_allocation, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.allocated_machine_id_mappings[
|
|
|
+ mock.sentinel.instance_id] = {}
|
|
|
+
|
|
|
+ result = self.task.execute(mock.sentinel.context)
|
|
|
+
|
|
|
+ self.assertIsNone(result)
|
|
|
+ mock_get_minion_machine.assert_not_called()
|
|
|
+ mock_confirm_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.action_id, {})
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_raises_exception_when_required_properties_are_missing(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.provider_properties = None
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState,
|
|
|
+ self.task.execute, mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin_minion_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask,
|
|
|
+ '_confirm_machine_allocation_for_action'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask, '_get_action_label'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_with_exception_not_found(
|
|
|
+ self, mock_get_minion_machine, mock_get_action_label,
|
|
|
+ mock_confirm_allocation):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_confirm_allocation.side_effect = exception.NotFound()
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.MinionMachineAllocationFailure,
|
|
|
+ self.task.execute, mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_action_label.assert_called_once_with()
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask, '_get_action_label'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks._BaseConfirmMinionAllocationForActionTask,
|
|
|
+ '_confirm_machine_allocation_for_action'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_raises_exception_when_invalid_migration_state(
|
|
|
+ self, mock_get_minion_machine, mock_confirm_allocation,
|
|
|
+ mock_get_action_label):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_confirm_allocation.side_effect = [
|
|
|
+ exception.InvalidReplicaState(reason='Invalid state')]
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.MinionMachineAllocationFailure,
|
|
|
+ self.task.execute, mock.sentinel.context)
|
|
|
+
|
|
|
+ mock_get_action_label.assert_called_once_with()
|
|
|
+
|
|
|
+
|
|
|
+class ConfirmMinionAllocationForMigrationTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(ConfirmMinionAllocationForMigrationTaskTestCase, self).setUp()
|
|
|
+ self.action_id = mock.sentinel.action_id
|
|
|
+
|
|
|
+ self.task = tasks.ConfirmMinionAllocationForMigrationTask(
|
|
|
+ mock.sentinel.action_id,
|
|
|
+ mock.sentinel.allocated_machine_id_mappings
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_action_label(self):
|
|
|
+ result = self.task._get_action_label()
|
|
|
+
|
|
|
+ self.assertEqual(result, 'migration')
|
|
|
+
|
|
|
+ def test_get_task_name(self):
|
|
|
+ result = self.task._get_task_name(self.action_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ f"migration-{self.action_id}-minion-allocation-confirmation"
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ ConductorClient, 'confirm_migration_minions_allocation'
|
|
|
+ )
|
|
|
+ def test__confirm_machine_allocation_for_action(
|
|
|
+ self, mock_confirm_migration_minions_allocation):
|
|
|
+ result = self.task._confirm_machine_allocation_for_action(
|
|
|
+ mock.sentinel.context, self.action_id,
|
|
|
+ mock.sentinel.machine_allocations)
|
|
|
+
|
|
|
+ self.assertIsNone(result)
|
|
|
+ mock_confirm_migration_minions_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.action_id,
|
|
|
+ mock.sentinel.machine_allocations)
|
|
|
+
|
|
|
+
|
|
|
+class ConfirmMinionAllocationForReplicaTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(ConfirmMinionAllocationForReplicaTaskTestCase, self).setUp()
|
|
|
+ self.task = tasks.ConfirmMinionAllocationForReplicaTask(
|
|
|
+ mock.sentinel.action_id,
|
|
|
+ mock.sentinel.allocate_machine_id_mappings
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_action_label(self):
|
|
|
+ result = self.task._get_action_label()
|
|
|
+
|
|
|
+ self.assertEqual(result, 'replica')
|
|
|
+
|
|
|
+ def test_get_task_name(self):
|
|
|
+ result = self.task._get_task_name(mock.sentinel.action_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ f"replica-{mock.sentinel.action_id}-minion-allocation-confirmation"
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ ConductorClient, 'confirm_replica_minions_allocation'
|
|
|
+ )
|
|
|
+ def test__confirm_machine_allocation_for_action(
|
|
|
+ self, mock_confirm_replica_minions_allocation):
|
|
|
+ result = self.task._confirm_machine_allocation_for_action(
|
|
|
+ mock.sentinel.context, mock.sentinel.action_id,
|
|
|
+ mock.sentinel.machine_allocations)
|
|
|
+
|
|
|
+ self.assertIsNone(result)
|
|
|
+ mock_confirm_replica_minions_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.action_id,
|
|
|
+ mock.sentinel.machine_allocations)
|
|
|
+
|
|
|
+
|
|
|
+class UpdateMinionPoolStatusTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis UpdateMinionPoolStatusTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(UpdateMinionPoolStatusTaskTestCase, self).setUp()
|
|
|
+ self.status_to_revert_to = mock.sentinel.status_to_revert_to
|
|
|
+
|
|
|
+ self.task = tasks.UpdateMinionPoolStatusTask(
|
|
|
+ mock.sentinel.minion_pool_id, mock.sentinel.status,
|
|
|
+ status_to_revert_to=self.status_to_revert_to)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_pool_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ def test_execute(self, mock_get_minion_pool, mock_set_minion_pool_status,
|
|
|
+ mock_add_minion_pool_event):
|
|
|
+ result = self.task.execute(mock.sentinel.context)
|
|
|
+ self.assertEqual(result, self.task._target_status)
|
|
|
+
|
|
|
+ mock_get_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ include_machines=False, include_events=False,
|
|
|
+ include_progress_updates=False)
|
|
|
+
|
|
|
+ mock_set_minion_pool_status.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ self.task._target_status)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_pool_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ def test_execute_when_previous_status_equals_target_status(
|
|
|
+ self, mock_get_minion_pool, mock_set_minion_pool_status):
|
|
|
+ self.task._previous_status = self.task._target_status
|
|
|
+
|
|
|
+ result = self.task.execute(mock.sentinel.context)
|
|
|
+ self.assertEqual(result, self.task._target_status)
|
|
|
+
|
|
|
+ mock_get_minion_pool.assert_not_called()
|
|
|
+ mock_set_minion_pool_status.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_pool_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ def test_revert(self, mock_get_minion_pool, mock_set_minion_pool_status,
|
|
|
+ mock_add_minion_pool_event):
|
|
|
+ mock_get_minion_pool.return_value.status = 'DEALLOCATED'
|
|
|
+
|
|
|
+ result = self.task.revert(mock.sentinel.context)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ include_machines=False, include_events=False,
|
|
|
+ include_progress_updates=False)
|
|
|
+
|
|
|
+ mock_set_minion_pool_status.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ self.status_to_revert_to)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_pool_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ def test_revert_no_minion_pool(self, mock_get_minion_pool,
|
|
|
+ mock_set_minion_pool_status):
|
|
|
+ mock_get_minion_pool.return_value = None
|
|
|
+
|
|
|
+ result = self.task.revert(mock.sentinel.context)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_set_minion_pool_status.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_pool_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ def test_revert_when_previous_status_equals_target_status(
|
|
|
+ self, mock_get_minion_pool, mock_set_minion_pool_status):
|
|
|
+ mock_get_minion_pool.return_value.status = self.status_to_revert_to
|
|
|
+
|
|
|
+ result = self.task.revert(mock.sentinel.context)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.minion_pool_id,
|
|
|
+ include_machines=False, include_events=False,
|
|
|
+ include_progress_updates=False)
|
|
|
+
|
|
|
+ mock_set_minion_pool_status.assert_not_called()
|
|
|
+
|
|
|
+
|
|
|
+class BaseMinionManangerTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis BaseMinionManangerTask class."""
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.BaseMinionManangerTask, '__abstractmethods__', set()
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, '_get_task_name')
|
|
|
+ def setUp(self, mock_get_task_name):
|
|
|
+ super(BaseMinionManangerTaskTestCase, self).setUp()
|
|
|
+ self.task = tasks.BaseMinionManangerTask(
|
|
|
+ mock.sentinel.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ mock.sentinel.main_task_runner_type)
|
|
|
+
|
|
|
+ @mock.patch.object(base.BaseRunWorkerTask, 'execute')
|
|
|
+ def test_execute(self, mock_execute):
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertEqual(result, mock_execute.return_value)
|
|
|
+
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event')
|
|
|
+ @mock.patch.object(base.BaseRunWorkerTask, 'revert')
|
|
|
+ def test_revert(self, mock_revert, mock_add_minion_pool_event):
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_revert.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+class ValidateMinionPoolOptionsTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis ValidateMinionPoolOptionsTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(ValidateMinionPoolOptionsTaskTestCase, self).setUp()
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+
|
|
|
+ self.task = tasks.ValidateMinionPoolOptionsTask(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.ValidateMinionPoolOptionsTask(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_VALIDATE_DESTINATION_MINION_POOL_OPTIONS
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_VALIDATION_TASK_NAME_FORMAT % self.minion_pool_id
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute(self, mock_execute, mock_add_minion_pool_event):
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ def test_revert(self, mock_revert):
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_revert.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+class AllocateSharedPoolResourcesTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis AllocateSharedPoolResourcesTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(AllocateSharedPoolResourcesTaskTestCase, self).setUp()
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+ self.task_info = {
|
|
|
+ 'pool_shared_resources': True
|
|
|
+ }
|
|
|
+
|
|
|
+ self.task = tasks.AllocateSharedPoolResourcesTask(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.AllocateSharedPoolResourcesTask(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_SET_UP_DESTINATION_POOL_SHARED_RESOURCES
|
|
|
+ )
|
|
|
+ self.assertEqual(
|
|
|
+ task._cleanup_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES # noqa: E501
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_ALLOCATE_SHARED_RESOURCES_TASK_NAME_FORMAT %
|
|
|
+ self.minion_pool_id
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_pool')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ def test_execute(self, mock_get_minion_pool_lock, mock_update_minion_pool,
|
|
|
+ mock_execute, mock_add_minion_pool_event,
|
|
|
+ mock_get_minion_pool):
|
|
|
+ mock_execute.return_value = {
|
|
|
+ 'pool_shared_resources': {"resource1": "id1"}
|
|
|
+ }
|
|
|
+ mock_get_minion_pool.return_value.shared_resources = {}
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(
|
|
|
+ result, {'pool_shared_resources': {"resource1": "id1"}})
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_get_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id)
|
|
|
+ mock_update_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id,
|
|
|
+ {'shared_resources': {"resource1": "id1"}})
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_pool')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ def test_execute_shared_resources_already_allocated(
|
|
|
+ self, mock_get_minion_pool_lock, mock_update_minion_pool,
|
|
|
+ mock_execute, mock_get_minion_pool):
|
|
|
+ mock_get_minion_pool.return_value.shared_resources = True
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionPoolState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_get_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id)
|
|
|
+ mock_execute.assert_not_called()
|
|
|
+ mock_update_minion_pool.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_pool')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_pool')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ def test_execute_no_minion_pool(
|
|
|
+ self, mock_get_minion_pool_lock, mock_update_minion_pool,
|
|
|
+ mock_execute, mock_get_minion_pool):
|
|
|
+ mock_get_minion_pool.return_value = None
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionPoolSelection, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_get_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id)
|
|
|
+ mock_execute.assert_not_called()
|
|
|
+ mock_update_minion_pool.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_pool')
|
|
|
+ def test_revert(self, mock_update_minion_pool, mock_get_minion_pool_lock,
|
|
|
+ mock_revert):
|
|
|
+ self.task_info = {}
|
|
|
+ self.update_values = {
|
|
|
+ 'pool_shared_resources': None
|
|
|
+ }
|
|
|
+
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertIsNone(result)
|
|
|
+ self.assertEqual(self.task_info['pool_shared_resources'], {})
|
|
|
+
|
|
|
+ mock_revert.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info
|
|
|
+ )
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_update_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.update_values)
|
|
|
+
|
|
|
+
|
|
|
+class DeallocateSharedPoolResourcesTaskTestCase(
|
|
|
+ test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis DeallocateSharedPoolResourcesTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(DeallocateSharedPoolResourcesTaskTestCase, self).setUp()
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.task_info = {
|
|
|
+ 'pool_shared_resources': {"resource1": "id1"},
|
|
|
+ 'pool_environment_options': {'option1': 'value1'}
|
|
|
+ }
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+
|
|
|
+ self.task = tasks.DeallocateSharedPoolResourcesTask(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.DeallocateSharedPoolResourcesTask(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES # noqa: E501
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, mock.sentinel.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_DEALLOCATE_SHARED_RESOURCES_TASK_NAME_FORMAT %
|
|
|
+ self.minion_pool_id
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_pool')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute(self, mock_execute, mock_update_minion_pool,
|
|
|
+ mock_add_minion_pool_event):
|
|
|
+ self.update_values = {
|
|
|
+ 'shared_resources': None,
|
|
|
+ }
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ mock_update_minion_pool.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.update_values)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'update_minion_pool')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute_no_pool_shared_resources(
|
|
|
+ self, mock_execute, mock_update_minion_pool,
|
|
|
+ mock_add_minion_pool_event):
|
|
|
+ self.task_info = {}
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidInput, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_execute.assert_not_called()
|
|
|
+ mock_update_minion_pool.assert_not_called()
|
|
|
+
|
|
|
+
|
|
|
+class AllocateMinionMachineTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis AllocateMinionMachineTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(AllocateMinionMachineTaskTestCase, self).setUp()
|
|
|
+ self.minion_machine = mock.MagicMock()
|
|
|
+ self.minion_machine.id = 'test_machine_id'
|
|
|
+ self.minion_machine.pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine.allocation_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_UNINITIALIZED)
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+ self.minion_machine.allocated_action = mock.sentinel.allocation_action
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine_id = 'test_machine_id'
|
|
|
+ self.task_info = {
|
|
|
+ 'pool_environment_options': 'test_env_options',
|
|
|
+ 'pool_shared_resources': True,
|
|
|
+ 'pool_identifier': 'test_identifier',
|
|
|
+ 'pool_os_type': 'linux',
|
|
|
+ }
|
|
|
+ self.mock_failure = mock.MagicMock(spec=failure.Failure)
|
|
|
+
|
|
|
+ self.task = tasks.AllocateMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.task._allocate_to_action = self.minion_machine.allocated_action
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.AllocateMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_CREATE_DESTINATION_MINION_MACHINE
|
|
|
+ )
|
|
|
+ self.assertEqual(
|
|
|
+ task._cleanup_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_DELETE_DESTINATION_MINION_MACHINE
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, self.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_ALLOCATE_MACHINE_TASK_NAME_FORMAT %
|
|
|
+ (self.minion_pool_id, self.minion_machine_id)
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_update_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.timeutils, 'utcnow')
|
|
|
+ @mock.patch.object(tasks.models, 'MinionMachine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'add_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute(
|
|
|
+ self, mock_execute, mock_add_minion_machine, mock_minion_machine,
|
|
|
+ mock_utcnow, mock_set_minion_machine_allocation,
|
|
|
+ mock_add_minion_pool_event, mock_update_minion_machine,
|
|
|
+ mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_execute.return_value = {
|
|
|
+ 'minion_connection_info': 'test_connection_info',
|
|
|
+ 'minion_provider_properties': 'test_provider_properties',
|
|
|
+ 'minion_backup_writer_connection_info': (
|
|
|
+ 'test_backup_writer_connection_info'),
|
|
|
+ }
|
|
|
+ expected_updated_values = {
|
|
|
+ 'last_used_at': mock_utcnow.return_value,
|
|
|
+ 'allocation_status': (
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_IN_USE),
|
|
|
+ 'power_status': (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_ON),
|
|
|
+ 'connection_info': 'test_connection_info',
|
|
|
+ 'provider_properties': 'test_provider_properties',
|
|
|
+ 'backup_writer_connection_info': (
|
|
|
+ 'test_backup_writer_connection_info'),
|
|
|
+ 'allocated_action': self.task._allocate_to_action
|
|
|
+ }
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_ALLOCATING)
|
|
|
+ mock_minion_machine.assert_not_called()
|
|
|
+ mock_add_minion_machine.assert_not_called()
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ mock_update_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ expected_updated_values)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_when_allocation_status_is_not_uninitialized(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.allocation_status = 'ALLOCATING'
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_when_minion_machine_belongs_to_different_pool(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.pool_id = 'DIFFERENT_POOL_ID'
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_when_minion_machine_already_allocated(
|
|
|
+ self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.task._allocate_to_action = 'ANOTHER_ACTION'
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_update_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.models, 'MinionMachine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'add_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute_add_new_minion_machine(
|
|
|
+ self, mock_execute, mock_add_minion_machine, mock_minion_machine,
|
|
|
+ mock_set_minion_machine_allocation, mock_add_minion_pool_event,
|
|
|
+ mock_update_minion_machine, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = None
|
|
|
+ mock_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_execute.side_effect = CoriolisTestException
|
|
|
+
|
|
|
+ self.assertRaises(CoriolisTestException, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_minion_machine.assert_called_once_with()
|
|
|
+ mock_add_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_ERROR_DEPLOYING)
|
|
|
+ mock_update_minion_machine.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ def test_revert(self, mock_revert, mock_delete_minion_machine,
|
|
|
+ mock_get_minion_machine, mock_get_minion_pool_lock):
|
|
|
+ self.task_info['minion_provider_properties'] = (
|
|
|
+ mock_get_minion_machine.return_value.provider_properties)
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.mock_failure.traceback_str = 'test_traceback'
|
|
|
+ kwargs = {'result': self.mock_failure}
|
|
|
+
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info, **kwargs)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_delete_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_revert.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info, **kwargs
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ def test_revert_failed_deletion(
|
|
|
+ self, mock_revert, mock_delete_minion_machine,
|
|
|
+ mock_get_minion_machine, mock_get_minion_pool_lock):
|
|
|
+ mock_get_minion_machine.return_value = None
|
|
|
+ mock_delete_minion_machine.side_effect = CoriolisTestException
|
|
|
+
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_revert.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ def test_revert_unexpected_result_type(
|
|
|
+ self, mock_revert, mock_delete_minion_machine,
|
|
|
+ mock_get_minion_machine, mock_get_minion_pool_lock):
|
|
|
+ self.task_info['minion_provider_properties'] = (
|
|
|
+ mock_get_minion_machine.return_value.provider_properties)
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ kwargs = {'result': 'test_result'}
|
|
|
+
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info, **kwargs)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_delete_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_revert.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info, **kwargs
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ def test_revert_raises_unhandled_exception(
|
|
|
+ self, mock_revert, mock_delete_minion_machine,
|
|
|
+ mock_get_minion_machine, mock_get_minion_pool_lock):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_revert.side_effect = CoriolisTestException
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ CoriolisTestException, self.task.revert,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_delete_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ @mock.patch.object(tasks.db_api, 'get_minion_machine')
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'revert')
|
|
|
+ def test_revert_no_raise_on_cleanup_failure(
|
|
|
+ self, mock_revert, mock_delete_minion_machine,
|
|
|
+ mock_get_minion_machine, mock_get_minion_pool_lock):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.task._raise_on_cleanup_failure = False
|
|
|
+ mock_revert.side_effect = CoriolisTestException
|
|
|
+
|
|
|
+ result = self.task.revert(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertIsNone(result)
|
|
|
+
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_delete_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+
|
|
|
+
|
|
|
+class DeallocateMinionMachineTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis DeallocateMinionMachineTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(DeallocateMinionMachineTaskTestCase, self).setUp()
|
|
|
+ self.minion_machine = mock.MagicMock()
|
|
|
+ self.minion_machine.id = 'test_machine_id'
|
|
|
+ self.minion_machine.pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine.allocation_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_IN_USE)
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+ self.minion_machine.allocated_action = mock.sentinel.allocation_action
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine_id = 'test_machine_id'
|
|
|
+ self.task_info = {
|
|
|
+ 'minion_provider_properties': None,
|
|
|
+ }
|
|
|
+ self.mock_failure = mock.MagicMock(spec=failure.Failure)
|
|
|
+
|
|
|
+ self.task = tasks.DeallocateMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.task._deallocate_from_action = (
|
|
|
+ self.minion_machine.allocated_action)
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.DeallocateMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_DELETE_DESTINATION_MINION_MACHINE
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, self.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_DEALLOCATE_MACHINE_TASK_NAME_FORMAT %
|
|
|
+ (self.minion_pool_id, self.minion_machine_id)
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ def test_execute(
|
|
|
+ self, mock_get_minion_pool_lock, mock_execute,
|
|
|
+ mock_delete_minion_machine, mock_set_minion_machine_allocation,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.provider_properties = None
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_set_minion_machine_allocation.assert_not_called()
|
|
|
+ mock_execute.assert_not_called()
|
|
|
+ mock_delete_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_no_machine(self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = None
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ def test_execute_with_provider_properties(
|
|
|
+ self, mock_get_minion_pool_lock, mock_execute,
|
|
|
+ mock_delete_minion_machine, mock_set_minion_machine_allocation,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.task_info['minion_provider_properties'] = (
|
|
|
+ mock_get_minion_machine.return_value.provider_properties)
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_DEALLOCATING)
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ mock_delete_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_get_minion_pool_lock.assert_called_once_with(
|
|
|
+ self.minion_pool_id, external=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.db_api, 'delete_minion_machine')
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(tasks.minion_manager_utils, 'get_minion_pool_lock')
|
|
|
+ def test_execute_with_exception(
|
|
|
+ self, mock_get_minion_pool_lock, mock_execute,
|
|
|
+ mock_delete_minion_machine, mock_set_minion_machine_allocation,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_execute.side_effect = CoriolisTestException
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ CoriolisTestException, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_DEALLOCATING)
|
|
|
+ mock_delete_minion_machine.assert_not_called()
|
|
|
+ mock_get_minion_pool_lock.assert_not_called()
|
|
|
+
|
|
|
+
|
|
|
+class HealthcheckMinionMachineTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis HealthcheckMinionMachineTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(HealthcheckMinionMachineTaskTestCase, self).setUp()
|
|
|
+ self.minion_machine = mock.MagicMock()
|
|
|
+ self.minion_machine.id = 'test_machine_id'
|
|
|
+ self.minion_machine.pool_id = 'test_pool_id'
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+ self.minion_machine.allocated_action = mock.sentinel.allocation_action
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine_id = 'test_machine_id'
|
|
|
+ self.task = tasks.HealthcheckMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id, self.minion_pool_type,
|
|
|
+ machine_status_on_success=(
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_AVAILABLE))
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.HealthcheckMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_HEALTHCHECK_DESTINATION_MINION
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute(
|
|
|
+ self, mock_set_minion_machine_allocation, mock_execute,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ execution_info = {
|
|
|
+ 'minion_provider_properties': (
|
|
|
+ mock_get_minion_machine.return_value.provider_properties),
|
|
|
+ 'minion_connection_info': (
|
|
|
+ mock_get_minion_machine.return_value.connection_info),
|
|
|
+ }
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertEqual(result['healthy'], True)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, execution_info)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_AVAILABLE)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute_no_machine(
|
|
|
+ self, mock_set_minion_machine_allocation, mock_execute,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = None
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertEqual(result['healthy'], False)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_set_minion_machine_allocation.assert_not_called()
|
|
|
+ mock_execute.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ def test_execute_no_machine_with_fail_on_error(
|
|
|
+ self, mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ self.task._fail_on_error = True
|
|
|
+ mock_get_minion_machine.return_value = None
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute_with_allocation_status(
|
|
|
+ self, mock_set_minion_machine_allocation, mock_execute,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ self.minion_machine.allocation_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_ERROR)
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertEqual(result['healthy'], False)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_set_minion_machine_allocation.assert_not_called()
|
|
|
+ mock_execute.assert_not_called()
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ def test_execute_with_allocation_status_and_fail_on_error(
|
|
|
+ self, mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ self.minion_machine.allocation_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_ERROR)
|
|
|
+ self.task._fail_on_error = True
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute_with_exception(
|
|
|
+ self, mock_set_minion_machine_allocation, mock_execute,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_execute.side_effect = CoriolisTestException
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+ self.assertEqual(result['healthy'], False)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_ERROR)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute_with_exception_and_fail_on_error(
|
|
|
+ self, mock_set_minion_machine_allocation, mock_execute,
|
|
|
+ mock_add_minion_pool_event, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_execute.side_effect = CoriolisTestException
|
|
|
+ self.task._fail_on_error = True
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ CoriolisTestException, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, mock.sentinel.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=False)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_ERROR)
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, self.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_HEALTHCHECK_MACHINE_TASK_NAME_FORMAT %
|
|
|
+ (self.minion_pool_id, self.minion_machine_id)
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+class MinionMachineHealtchcheckDeciderTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis MinionMachineHealtchcheckDecider class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(MinionMachineHealtchcheckDeciderTestCase, self).setUp()
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine_id = 'test_machine_id'
|
|
|
+ self.healthcheck_task_name = (
|
|
|
+ tasks.MINION_POOL_HEALTHCHECK_MACHINE_TASK_NAME_FORMAT %
|
|
|
+ (self.minion_pool_id, self.minion_machine_id)
|
|
|
+ )
|
|
|
+
|
|
|
+ self.task = tasks.MinionMachineHealtchcheckDecider(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ on_successful_healthcheck=True)
|
|
|
+
|
|
|
+ def test_call_with_empty_history(self):
|
|
|
+ history = {}
|
|
|
+
|
|
|
+ result = self.task.__call__(history)
|
|
|
+ self.assertFalse(result)
|
|
|
+
|
|
|
+ def test_call_with_healthy_result(self):
|
|
|
+ history = {
|
|
|
+ self.healthcheck_task_name: {
|
|
|
+ "healthy": True
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ result = self.task.__call__(history)
|
|
|
+ self.assertEqual(result, self.task._on_success)
|
|
|
+
|
|
|
+ def test_call_with_unhealthy_result(self):
|
|
|
+ history = {
|
|
|
+ self.healthcheck_task_name: {
|
|
|
+ "healthy": False
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ result = self.task.__call__(history)
|
|
|
+ self.assertEqual(result, not self.task._on_success)
|
|
|
+
|
|
|
+
|
|
|
+class PowerOnMinionMachineTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis PowerOnMinionMachineTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(PowerOnMinionMachineTaskTestCase, self).setUp()
|
|
|
+ self.minion_machine = mock.MagicMock()
|
|
|
+ self.minion_machine.id = 'test_machine_id'
|
|
|
+ self.minion_machine.pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine.allocated_action = mock.sentinel.allocation_action
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine_id = 'test_machine_id'
|
|
|
+ self.task_info = {
|
|
|
+ 'minion_provider_properties': None,
|
|
|
+ }
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+ self.minion_machine.power_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_OFF)
|
|
|
+
|
|
|
+ self.task = tasks.PowerOnMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id, self.minion_pool_type)
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.PowerOnMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_POWER_ON_DESTINATION_MINION
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, self.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_POWER_ON_MACHINE_TASK_NAME_FORMAT %
|
|
|
+ (self.minion_pool_id, self.minion_machine_id)
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_machine_power_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute(self, mock_execute, mock_add_minion_pool_event,
|
|
|
+ mock_set_minion_machine_power_status,
|
|
|
+ mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.power_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_OFF)
|
|
|
+ self.task_info['minion_provider_properties'] = (
|
|
|
+ mock_get_minion_machine.return_value.provider_properties)
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+ mock_set_minion_machine_power_status.assert_has_calls([
|
|
|
+ mock.call(
|
|
|
+ mock.sentinel.context, self.minion_pool_id,
|
|
|
+ self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERING_ON
|
|
|
+ ),
|
|
|
+ mock.call(
|
|
|
+ mock.sentinel.context, self.minion_pool_id,
|
|
|
+ self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_ON)
|
|
|
+ ])
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_power_on(self, mock_get_minion_machine):
|
|
|
+ self.minion_machine.power_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_ON)
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_invalid_power_status(self, mock_get_minion_machine):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.minion_machine.power_status = 'INVALID_POWER_STATUS'
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.InvalidMinionMachineState, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_machine_power_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute_with_exception(
|
|
|
+ self, mock_set_minion_machine_allocation,
|
|
|
+ mock_get_minion_machine, mock_add_minion_pool_event,
|
|
|
+ mock_set_minion_machine_power_status):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_set_minion_machine_power_status.side_effect = (
|
|
|
+ exception.CoriolisException)
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.CoriolisException, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_POWER_ERROR)
|
|
|
+
|
|
|
+
|
|
|
+class PowerOffMinionMachineTaskTestCase(test_base.CoriolisBaseTestCase):
|
|
|
+ """Test suite for the Coriolis PowerOffMinionMachineTask class."""
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super(PowerOffMinionMachineTaskTestCase, self).setUp()
|
|
|
+ self.minion_machine = mock.MagicMock()
|
|
|
+ self.minion_machine.id = 'test_machine_id'
|
|
|
+ self.minion_machine.pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine.allocated_action = mock.sentinel.allocation_action
|
|
|
+ self.minion_pool_type = tasks.constants.PROVIDER_PLATFORM_SOURCE
|
|
|
+ self.minion_pool_id = 'test_pool_id'
|
|
|
+ self.minion_machine_id = 'test_machine_id'
|
|
|
+ self.task_info = {
|
|
|
+ 'minion_provider_properties': None,
|
|
|
+ }
|
|
|
+ self.minion_machine.power_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_ON)
|
|
|
+
|
|
|
+ self.task = tasks.PowerOffMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id, self.minion_pool_type)
|
|
|
+
|
|
|
+ def test__init__with_different_minion_pool_type(self):
|
|
|
+ self.minion_pool_type = "destination"
|
|
|
+
|
|
|
+ task = tasks.PowerOffMinionMachineTask(
|
|
|
+ self.minion_pool_id, self.minion_machine_id,
|
|
|
+ self.minion_pool_type)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ task._main_task_runner_type,
|
|
|
+ tasks.constants.TASK_TYPE_POWER_OFF_DESTINATION_MINION
|
|
|
+ )
|
|
|
+
|
|
|
+ def test__get_task_name(self):
|
|
|
+ result = self.task._get_task_name(
|
|
|
+ self.minion_pool_id, self.minion_machine_id)
|
|
|
+
|
|
|
+ self.assertEqual(
|
|
|
+ result,
|
|
|
+ tasks.MINION_POOL_POWER_OFF_MACHINE_TASK_NAME_FORMAT %
|
|
|
+ (self.minion_pool_id, self.minion_machine_id)
|
|
|
+ )
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_machine_power_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(tasks.BaseMinionManangerTask, 'execute')
|
|
|
+ def test_execute(self, mock_execute, mock_set_minion_machine_allocation,
|
|
|
+ mock_get_minion_machine, mock_add_minion_pool_event,
|
|
|
+ mock_set_minion_machine_power_status):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ self.task_info['minion_provider_properties'] = (
|
|
|
+ mock_get_minion_machine.return_value.provider_properties)
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_execute.assert_called_once_with(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+ mock_set_minion_machine_power_status.assert_has_calls([
|
|
|
+ mock.call(
|
|
|
+ mock.sentinel.context, self.minion_pool_id,
|
|
|
+ self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERING_OFF
|
|
|
+ ),
|
|
|
+ mock.call(
|
|
|
+ mock.sentinel.context, self.minion_pool_id,
|
|
|
+ self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_OFF)
|
|
|
+ ])
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_AVAILABLE)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ def test_execute_power_off(self, mock_get_minion_machine):
|
|
|
+ self.minion_machine.power_status = (
|
|
|
+ tasks.constants.MINION_MACHINE_POWER_STATUS_POWERED_OFF)
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+
|
|
|
+ result = self.task.execute(
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+ self.assertEqual(result, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_set_minion_machine_power_status'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_add_minion_pool_event'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin, '_get_minion_machine'
|
|
|
+ )
|
|
|
+ @mock.patch.object(
|
|
|
+ tasks.MinionManagerTaskEventMixin,
|
|
|
+ '_set_minion_machine_allocation_status'
|
|
|
+ )
|
|
|
+ def test_execute_with_exception(
|
|
|
+ self, mock_set_minion_machine_allocation,
|
|
|
+ mock_get_minion_machine, mock_add_minion_pool_event,
|
|
|
+ mock_set_minion_machine_power_status):
|
|
|
+ mock_get_minion_machine.return_value = self.minion_machine
|
|
|
+ mock_set_minion_machine_power_status.side_effect = (
|
|
|
+ exception.CoriolisException)
|
|
|
+
|
|
|
+ self.assertRaises(
|
|
|
+ exception.CoriolisException, self.task.execute,
|
|
|
+ mock.sentinel.context, mock.sentinel.origin,
|
|
|
+ mock.sentinel.destination, self.task_info)
|
|
|
+
|
|
|
+ mock_get_minion_machine.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_machine_id,
|
|
|
+ raise_if_not_found=True)
|
|
|
+ mock_set_minion_machine_allocation.assert_called_once_with(
|
|
|
+ mock.sentinel.context, self.minion_pool_id, self.minion_machine_id,
|
|
|
+ tasks.constants.MINION_MACHINE_STATUS_POWER_ERROR)
|