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
This commit is contained in:
Zhenguo Niu 2017-03-23 15:21:05 +08:00
parent c2cf94d947
commit 7a341d8e04
6 changed files with 25 additions and 56 deletions

View File

@ -36,25 +36,6 @@ ACTION = 'instance:create'
CONF = cfg.CONF 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): class OnFailureRescheduleTask(flow_utils.MoganTask):
"""Triggers a rescheduling request to be sent when reverting occurs. """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: This flow will do the following:
1. Schedule a node to create instance 1. Build networks for the instance and set port id back to baremetal port
3. Build networks for the instance and set port id back to baremetal port 2. Do node deploy and handle errors.
4. Do node deploy and handle errors. 3. Reschedule if the tasks are on failure.
""" """
flow_name = ACTION.replace(":", "_") + "_manager" flow_name = ACTION.replace(":", "_") + "_manager"
@ -265,8 +246,7 @@ def get_flow(context, manager, instance, requested_networks, request_spec,
'requested_networks': requested_networks 'requested_networks': requested_networks
} }
instance_flow.add(ScheduleCreateInstanceTask(manager), instance_flow.add(OnFailureRescheduleTask(manager.engine_rpcapi),
OnFailureRescheduleTask(manager.engine_rpcapi),
BuildNetworkTask(manager), BuildNetworkTask(manager),
CreateInstanceTask(manager.driver)) CreateInstanceTask(manager.driver))

View File

@ -326,6 +326,19 @@ class EngineManager(base_manager.BaseEngineManager):
if filter_properties is None: if filter_properties is None:
filter_properties = {} 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: try:
flow_engine = create_instance.get_flow( flow_engine = create_instance.get_flow(
context, context,
@ -336,6 +349,7 @@ class EngineManager(base_manager.BaseEngineManager):
filter_properties, filter_properties,
) )
except Exception: except Exception:
utils.process_event(fsm, instance, event='error')
msg = _("Create manager instance flow failed.") msg = _("Create manager instance flow failed.")
LOG.exception(msg) LOG.exception(msg)
raise exception.MoganException(msg) raise exception.MoganException(msg)

View File

@ -189,8 +189,9 @@ class FilterScheduler(driver.Scheduler):
top_node = self._choose_top_node(weighed_nodes, request_spec) top_node = self._choose_top_node(weighed_nodes, request_spec)
top_node.obj.consume_from_request(context) top_node.obj.consume_from_request(context)
self._add_retry_node(filter_properties, top_node.obj.node) self._add_retry_node(filter_properties, top_node.obj.node_uuid)
return top_node.obj.node dest = dict(node_uuid=top_node.obj.node_uuid)
return dest
return _schedule(self, context, request_spec, filter_properties) return _schedule(self, context, request_spec, filter_properties)

View File

@ -34,7 +34,7 @@ class NodeState(object):
"""Mutable and immutable information tracked for a Ironic node.""" """Mutable and immutable information tracked for a Ironic node."""
def __init__(self, node): def __init__(self, node):
self.node = node.node_uuid self.node_uuid = node.node_uuid
self.capabilities = node.extra_specs self.capabilities = node.extra_specs
self.availability_zone = node.availability_zone \ self.availability_zone = node.availability_zone \
or CONF.engine.default_availability_zone or CONF.engine.default_availability_zone
@ -43,7 +43,7 @@ class NodeState(object):
def consume_from_request(self, context): def consume_from_request(self, context):
"""Consume the compute node.""" """Consume the compute node."""
objects.ComputeNode.consume_node(context, self.node) objects.ComputeNode.consume_node(context, self.node_uuid)
class NodeManager(object): class NodeManager(object):

View File

@ -24,12 +24,12 @@ class WeighedNode(base_weight.WeighedObject):
def to_dict(self): def to_dict(self):
return { return {
'weight': self.weight, 'weight': self.weight,
'node': self.obj.node, 'node': self.obj.node_uuid,
} }
def __repr__(self): def __repr__(self):
return ("WeighedNode [node: %s, weight: %s]" % return ("WeighedNode [node: %s, weight: %s]" %
(self.obj.node, self.weight)) (self.obj.node_uuid, self.weight))
class BaseNodeWeigher(base_weight.BaseWeigher): class BaseNodeWeigher(base_weight.BaseWeigher):

View File

@ -16,13 +16,11 @@
import mock import mock
from oslo_context import context from oslo_context import context
from oslo_utils import uuidutils
from mogan.engine.baremetal.ironic import IronicDriver from mogan.engine.baremetal.ironic import IronicDriver
from mogan.engine.flows import create_instance from mogan.engine.flows import create_instance
from mogan.engine import manager from mogan.engine import manager
from mogan import objects from mogan import objects
from mogan.scheduler import rpcapi as scheduler_rpcapi
from mogan.tests import base from mogan.tests import base
from mogan.tests.unit.objects import utils as obj_utils from mogan.tests.unit.objects import utils as obj_utils
@ -33,30 +31,6 @@ class CreateInstanceFlowTestCase(base.TestCase):
super(CreateInstanceFlowTestCase, self).setUp() super(CreateInstanceFlowTestCase, self).setUp()
self.ctxt = context.get_admin_context() 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(objects.instance.Instance, 'save')
@mock.patch.object(create_instance.BuildNetworkTask, '_build_networks') @mock.patch.object(create_instance.BuildNetworkTask, '_build_networks')
def test_create_network_task_execute(self, mock_build_networks, mock_save): def test_create_network_task_execute(self, mock_build_networks, mock_save):