From 7a341d8e04a343d1f30a340b417086e73e590f5d Mon Sep 17 00:00:00 2001 From: Zhenguo Niu Date: Thu, 23 Mar 2017 15:21:05 +0800 Subject: [PATCH] Move schedule task out of create instance flow For multi instance creation scenario, we need to schedule for all requested instances first then run the flow separately, so better to move this task out, and leave the OnFailureReschedule task to the flow. Change-Id: If576003cd6a2db0dd90e2ee5cdf0b0cb00f6da63 --- mogan/engine/flows/create_instance.py | 28 +++---------------- mogan/engine/manager.py | 14 ++++++++++ mogan/scheduler/filter_scheduler.py | 5 ++-- mogan/scheduler/node_manager.py | 4 +-- mogan/scheduler/weights/__init__.py | 4 +-- .../engine/flows/test_create_instance_flow.py | 26 ----------------- 6 files changed, 25 insertions(+), 56 deletions(-) diff --git a/mogan/engine/flows/create_instance.py b/mogan/engine/flows/create_instance.py index 46d45557..e4ab3f48 100644 --- a/mogan/engine/flows/create_instance.py +++ b/mogan/engine/flows/create_instance.py @@ -36,25 +36,6 @@ ACTION = 'instance:create' CONF = cfg.CONF -class ScheduleCreateInstanceTask(flow_utils.MoganTask): - """Activates a scheduler driver and handles any subsequent failure.""" - - def __init__(self, manager): - requires = ['filter_properties', 'request_spec', 'instance', - 'context'] - super(ScheduleCreateInstanceTask, self).__init__(addons=[ACTION], - requires=requires) - self.manager = manager - - def execute(self, context, instance, request_spec, filter_properties): - top_node = self.manager.scheduler_rpcapi.select_destinations( - context, - request_spec, - filter_properties) - instance.node_uuid = top_node - instance.save() - - class OnFailureRescheduleTask(flow_utils.MoganTask): """Triggers a rescheduling request to be sent when reverting occurs. @@ -246,9 +227,9 @@ def get_flow(context, manager, instance, requested_networks, request_spec, This flow will do the following: - 1. Schedule a node to create instance - 3. Build networks for the instance and set port id back to baremetal port - 4. Do node deploy and handle errors. + 1. Build networks for the instance and set port id back to baremetal port + 2. Do node deploy and handle errors. + 3. Reschedule if the tasks are on failure. """ flow_name = ACTION.replace(":", "_") + "_manager" @@ -265,8 +246,7 @@ def get_flow(context, manager, instance, requested_networks, request_spec, 'requested_networks': requested_networks } - instance_flow.add(ScheduleCreateInstanceTask(manager), - OnFailureRescheduleTask(manager.engine_rpcapi), + instance_flow.add(OnFailureRescheduleTask(manager.engine_rpcapi), BuildNetworkTask(manager), CreateInstanceTask(manager.driver)) diff --git a/mogan/engine/manager.py b/mogan/engine/manager.py index 9f3f4b13..67bf53aa 100644 --- a/mogan/engine/manager.py +++ b/mogan/engine/manager.py @@ -326,6 +326,19 @@ class EngineManager(base_manager.BaseEngineManager): if filter_properties is None: filter_properties = {} + try: + node = self.scheduler_rpcapi.select_destinations( + context, request_spec, filter_properties) + instance.node_uuid = node['node_uuid'] + instance.save() + except Exception as e: + utils.process_event(fsm, instance, event='error') + LOG.error(_LE("Created instance %(uuid)s failed." + "Exception: %(exception)s"), + {"uuid": instance.uuid, + "exception": e}) + return + try: flow_engine = create_instance.get_flow( context, @@ -336,6 +349,7 @@ class EngineManager(base_manager.BaseEngineManager): filter_properties, ) except Exception: + utils.process_event(fsm, instance, event='error') msg = _("Create manager instance flow failed.") LOG.exception(msg) raise exception.MoganException(msg) diff --git a/mogan/scheduler/filter_scheduler.py b/mogan/scheduler/filter_scheduler.py index 557f2b6e..f573b413 100644 --- a/mogan/scheduler/filter_scheduler.py +++ b/mogan/scheduler/filter_scheduler.py @@ -189,8 +189,9 @@ class FilterScheduler(driver.Scheduler): top_node = self._choose_top_node(weighed_nodes, request_spec) top_node.obj.consume_from_request(context) - self._add_retry_node(filter_properties, top_node.obj.node) - return top_node.obj.node + self._add_retry_node(filter_properties, top_node.obj.node_uuid) + dest = dict(node_uuid=top_node.obj.node_uuid) + return dest return _schedule(self, context, request_spec, filter_properties) diff --git a/mogan/scheduler/node_manager.py b/mogan/scheduler/node_manager.py index f6b7db26..43cb6d41 100644 --- a/mogan/scheduler/node_manager.py +++ b/mogan/scheduler/node_manager.py @@ -34,7 +34,7 @@ class NodeState(object): """Mutable and immutable information tracked for a Ironic node.""" def __init__(self, node): - self.node = node.node_uuid + self.node_uuid = node.node_uuid self.capabilities = node.extra_specs self.availability_zone = node.availability_zone \ or CONF.engine.default_availability_zone @@ -43,7 +43,7 @@ class NodeState(object): def consume_from_request(self, context): """Consume the compute node.""" - objects.ComputeNode.consume_node(context, self.node) + objects.ComputeNode.consume_node(context, self.node_uuid) class NodeManager(object): diff --git a/mogan/scheduler/weights/__init__.py b/mogan/scheduler/weights/__init__.py index 0a9f59e4..a325e126 100644 --- a/mogan/scheduler/weights/__init__.py +++ b/mogan/scheduler/weights/__init__.py @@ -24,12 +24,12 @@ class WeighedNode(base_weight.WeighedObject): def to_dict(self): return { 'weight': self.weight, - 'node': self.obj.node, + 'node': self.obj.node_uuid, } def __repr__(self): return ("WeighedNode [node: %s, weight: %s]" % - (self.obj.node, self.weight)) + (self.obj.node_uuid, self.weight)) class BaseNodeWeigher(base_weight.BaseWeigher): diff --git a/mogan/tests/unit/engine/flows/test_create_instance_flow.py b/mogan/tests/unit/engine/flows/test_create_instance_flow.py index 33ab5750..a7788d03 100644 --- a/mogan/tests/unit/engine/flows/test_create_instance_flow.py +++ b/mogan/tests/unit/engine/flows/test_create_instance_flow.py @@ -16,13 +16,11 @@ import mock from oslo_context import context -from oslo_utils import uuidutils from mogan.engine.baremetal.ironic import IronicDriver from mogan.engine.flows import create_instance from mogan.engine import manager from mogan import objects -from mogan.scheduler import rpcapi as scheduler_rpcapi from mogan.tests import base from mogan.tests.unit.objects import utils as obj_utils @@ -33,30 +31,6 @@ class CreateInstanceFlowTestCase(base.TestCase): super(CreateInstanceFlowTestCase, self).setUp() self.ctxt = context.get_admin_context() - @mock.patch.object(objects.instance.Instance, 'save') - @mock.patch.object(scheduler_rpcapi.SchedulerAPI, 'select_destinations') - def test_schedule_task_execute(self, mock_schedule, mock_save): - fake_uuid = uuidutils.generate_uuid() - fake_engine_manager = mock.MagicMock() - sche_rpcapi = scheduler_rpcapi.SchedulerAPI() - fake_engine_manager.scheduler_rpcapi = sche_rpcapi - fake_request_spec = mock.MagicMock() - fake_filter_props = mock.MagicMock() - task = create_instance.ScheduleCreateInstanceTask( - fake_engine_manager) - instance_obj = obj_utils.get_test_instance(self.ctxt) - mock_schedule.return_value = fake_uuid - mock_save.side_effect = None - - task.execute(self.ctxt, - instance_obj, - fake_request_spec, - fake_filter_props) - mock_schedule.assert_called_once_with(self.ctxt, - fake_request_spec, - fake_filter_props) - self.assertEqual(fake_uuid, instance_obj.node_uuid) - @mock.patch.object(objects.instance.Instance, 'save') @mock.patch.object(create_instance.BuildNetworkTask, '_build_networks') def test_create_network_task_execute(self, mock_build_networks, mock_save):