Merge "Refactoring: finish splitting do_node_deploy"
This commit is contained in:
commit
cc38f03cf5
@ -21,7 +21,9 @@ from oslo_utils import excutils
|
|||||||
from oslo_utils import versionutils
|
from oslo_utils import versionutils
|
||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
|
from ironic.common.glance_service import service_utils as glance_utils
|
||||||
from ironic.common.i18n import _
|
from ironic.common.i18n import _
|
||||||
|
from ironic.common import images
|
||||||
from ironic.common import release_mappings as versions
|
from ironic.common import release_mappings as versions
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
from ironic.common import swift
|
from ironic.common import swift
|
||||||
@ -41,6 +43,91 @@ METRICS = metrics_utils.get_metrics_logger(__name__)
|
|||||||
_SEEN_NO_DEPLOY_STEP_DEPRECATIONS = set()
|
_SEEN_NO_DEPLOY_STEP_DEPRECATIONS = set()
|
||||||
|
|
||||||
|
|
||||||
|
def validate_node(task, event='deploy'):
|
||||||
|
"""Validate that a node is suitable for deployment/rebuilding.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:param event: event to process: deploy or rebuild.
|
||||||
|
:raises: NodeInMaintenance, NodeProtected, InvalidStateRequested
|
||||||
|
"""
|
||||||
|
if task.node.maintenance:
|
||||||
|
raise exception.NodeInMaintenance(op=_('provisioning'),
|
||||||
|
node=task.node.uuid)
|
||||||
|
|
||||||
|
if event == 'rebuild' and task.node.protected:
|
||||||
|
raise exception.NodeProtected(node=task.node.uuid)
|
||||||
|
|
||||||
|
if not task.fsm.is_actionable_event(event):
|
||||||
|
raise exception.InvalidStateRequested(
|
||||||
|
action=event, node=task.node.uuid, state=task.node.provision_state)
|
||||||
|
|
||||||
|
|
||||||
|
@METRICS.timer('start_deploy')
|
||||||
|
@task_manager.require_exclusive_lock
|
||||||
|
def start_deploy(task, manager, configdrive=None, event='deploy'):
|
||||||
|
"""Start deployment or rebuilding on a node.
|
||||||
|
|
||||||
|
This function does not check the node suitability for deployment, it's left
|
||||||
|
up to the caller.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:param manager: a ConductorManager to run tasks on.
|
||||||
|
:param configdrive: a configdrive, if requested.
|
||||||
|
:param event: event to process: deploy or rebuild.
|
||||||
|
"""
|
||||||
|
node = task.node
|
||||||
|
# Record of any pre-existing agent_url should be removed
|
||||||
|
# except when we are in fast track conditions.
|
||||||
|
if not utils.is_fast_track(task):
|
||||||
|
utils.remove_agent_url(node)
|
||||||
|
|
||||||
|
if event == 'rebuild':
|
||||||
|
# Note(gilliard) Clear these to force the driver to
|
||||||
|
# check whether they have been changed in glance
|
||||||
|
# NOTE(vdrok): If image_source is not from Glance we should
|
||||||
|
# not clear kernel and ramdisk as they're input manually
|
||||||
|
if glance_utils.is_glance_image(
|
||||||
|
node.instance_info.get('image_source')):
|
||||||
|
instance_info = node.instance_info
|
||||||
|
instance_info.pop('kernel', None)
|
||||||
|
instance_info.pop('ramdisk', None)
|
||||||
|
node.instance_info = instance_info
|
||||||
|
|
||||||
|
driver_internal_info = node.driver_internal_info
|
||||||
|
# Infer the image type to make sure the deploy driver
|
||||||
|
# validates only the necessary variables for different
|
||||||
|
# image types.
|
||||||
|
# NOTE(sirushtim): The iwdi variable can be None. It's up to
|
||||||
|
# the deploy driver to validate this.
|
||||||
|
iwdi = images.is_whole_disk_image(task.context, node.instance_info)
|
||||||
|
driver_internal_info['is_whole_disk_image'] = iwdi
|
||||||
|
node.driver_internal_info = driver_internal_info
|
||||||
|
node.save()
|
||||||
|
|
||||||
|
try:
|
||||||
|
task.driver.power.validate(task)
|
||||||
|
task.driver.deploy.validate(task)
|
||||||
|
utils.validate_instance_info_traits(task.node)
|
||||||
|
conductor_steps.validate_deploy_templates(task)
|
||||||
|
except exception.InvalidParameterValue as e:
|
||||||
|
raise exception.InstanceDeployFailure(
|
||||||
|
_("Failed to validate deploy or power info for node "
|
||||||
|
"%(node_uuid)s. Error: %(msg)s") %
|
||||||
|
{'node_uuid': node.uuid, 'msg': e}, code=e.code)
|
||||||
|
|
||||||
|
try:
|
||||||
|
task.process_event(
|
||||||
|
event,
|
||||||
|
callback=manager._spawn_worker,
|
||||||
|
call_args=(do_node_deploy, task,
|
||||||
|
manager.conductor.id, configdrive),
|
||||||
|
err_handler=utils.provisioning_error_handler)
|
||||||
|
except exception.InvalidState:
|
||||||
|
raise exception.InvalidStateRequested(
|
||||||
|
action=event, node=task.node.uuid,
|
||||||
|
state=task.node.provision_state)
|
||||||
|
|
||||||
|
|
||||||
@METRICS.timer('do_node_deploy')
|
@METRICS.timer('do_node_deploy')
|
||||||
@task_manager.require_exclusive_lock
|
@task_manager.require_exclusive_lock
|
||||||
def do_node_deploy(task, conductor_id=None, configdrive=None):
|
def do_node_deploy(task, conductor_id=None, configdrive=None):
|
||||||
|
@ -56,7 +56,6 @@ from oslo_utils import uuidutils
|
|||||||
from ironic.common import driver_factory
|
from ironic.common import driver_factory
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common import faults
|
from ironic.common import faults
|
||||||
from ironic.common.glance_service import service_utils as glance_utils
|
|
||||||
from ironic.common.i18n import _
|
from ironic.common.i18n import _
|
||||||
from ironic.common import images
|
from ironic.common import images
|
||||||
from ironic.common import network
|
from ironic.common import network
|
||||||
@ -822,6 +821,7 @@ class ConductorManager(base_manager.BaseConductorManager):
|
|||||||
:raises: NodeProtected if the node is protected.
|
:raises: NodeProtected if the node is protected.
|
||||||
"""
|
"""
|
||||||
LOG.debug("RPC do_node_deploy called for node %s.", node_id)
|
LOG.debug("RPC do_node_deploy called for node %s.", node_id)
|
||||||
|
event = 'rebuild' if rebuild else 'deploy'
|
||||||
|
|
||||||
# NOTE(comstud): If the _sync_power_states() periodic task happens
|
# NOTE(comstud): If the _sync_power_states() periodic task happens
|
||||||
# to have locked this node, we'll fail to acquire the lock. The
|
# to have locked this node, we'll fail to acquire the lock. The
|
||||||
@ -829,69 +829,8 @@ class ConductorManager(base_manager.BaseConductorManager):
|
|||||||
# want to add retries or extra synchronization here.
|
# want to add retries or extra synchronization here.
|
||||||
with task_manager.acquire(context, node_id, shared=False,
|
with task_manager.acquire(context, node_id, shared=False,
|
||||||
purpose='node deployment') as task:
|
purpose='node deployment') as task:
|
||||||
node = task.node
|
deployments.validate_node(task, event=event)
|
||||||
# Record of any pre-existing agent_url should be removed
|
deployments.start_deploy(task, self, configdrive, event=event)
|
||||||
# except when we are in fast track conditions.
|
|
||||||
if not utils.is_fast_track(task):
|
|
||||||
utils.remove_agent_url(node)
|
|
||||||
if node.maintenance:
|
|
||||||
raise exception.NodeInMaintenance(op=_('provisioning'),
|
|
||||||
node=node.uuid)
|
|
||||||
|
|
||||||
if rebuild:
|
|
||||||
if node.protected:
|
|
||||||
raise exception.NodeProtected(node=node.uuid)
|
|
||||||
|
|
||||||
event = 'rebuild'
|
|
||||||
|
|
||||||
# Note(gilliard) Clear these to force the driver to
|
|
||||||
# check whether they have been changed in glance
|
|
||||||
# NOTE(vdrok): If image_source is not from Glance we should
|
|
||||||
# not clear kernel and ramdisk as they're input manually
|
|
||||||
if glance_utils.is_glance_image(
|
|
||||||
node.instance_info.get('image_source')):
|
|
||||||
instance_info = node.instance_info
|
|
||||||
instance_info.pop('kernel', None)
|
|
||||||
instance_info.pop('ramdisk', None)
|
|
||||||
node.instance_info = instance_info
|
|
||||||
else:
|
|
||||||
event = 'deploy'
|
|
||||||
|
|
||||||
driver_internal_info = node.driver_internal_info
|
|
||||||
# Infer the image type to make sure the deploy driver
|
|
||||||
# validates only the necessary variables for different
|
|
||||||
# image types.
|
|
||||||
# NOTE(sirushtim): The iwdi variable can be None. It's up to
|
|
||||||
# the deploy driver to validate this.
|
|
||||||
iwdi = images.is_whole_disk_image(context, node.instance_info)
|
|
||||||
driver_internal_info['is_whole_disk_image'] = iwdi
|
|
||||||
node.driver_internal_info = driver_internal_info
|
|
||||||
node.save()
|
|
||||||
|
|
||||||
try:
|
|
||||||
task.driver.power.validate(task)
|
|
||||||
task.driver.deploy.validate(task)
|
|
||||||
utils.validate_instance_info_traits(task.node)
|
|
||||||
conductor_steps.validate_deploy_templates(task)
|
|
||||||
except exception.InvalidParameterValue as e:
|
|
||||||
raise exception.InstanceDeployFailure(
|
|
||||||
_("Failed to validate deploy or power info for node "
|
|
||||||
"%(node_uuid)s. Error: %(msg)s") %
|
|
||||||
{'node_uuid': node.uuid, 'msg': e}, code=e.code)
|
|
||||||
|
|
||||||
LOG.debug("do_node_deploy Calling event: %(event)s for node: "
|
|
||||||
"%(node)s", {'event': event, 'node': node.uuid})
|
|
||||||
try:
|
|
||||||
task.process_event(
|
|
||||||
event,
|
|
||||||
callback=self._spawn_worker,
|
|
||||||
call_args=(deployments.do_node_deploy, task,
|
|
||||||
self.conductor.id, configdrive),
|
|
||||||
err_handler=utils.provisioning_error_handler)
|
|
||||||
except exception.InvalidState:
|
|
||||||
raise exception.InvalidStateRequested(
|
|
||||||
action=event, node=task.node.uuid,
|
|
||||||
state=task.node.provision_state)
|
|
||||||
|
|
||||||
@METRICS.timer('ConductorManager.continue_node_deploy')
|
@METRICS.timer('ConductorManager.continue_node_deploy')
|
||||||
def continue_node_deploy(self, context, node_id):
|
def continue_node_deploy(self, context, node_id):
|
||||||
|
@ -1341,7 +1341,7 @@ class ServiceDoNodeDeployTestCase(mgr_utils.ServiceSetUpMixin,
|
|||||||
self.assertIsNone(node.last_error)
|
self.assertIsNone(node.last_error)
|
||||||
# Verify reservation has been cleared.
|
# Verify reservation has been cleared.
|
||||||
self.assertIsNone(node.reservation)
|
self.assertIsNone(node.reservation)
|
||||||
mock_iwdi.assert_called_once_with(self.context, node.instance_info)
|
self.assertFalse(mock_iwdi.called)
|
||||||
self.assertNotIn('is_whole_disk_image', node.driver_internal_info)
|
self.assertNotIn('is_whole_disk_image', node.driver_internal_info)
|
||||||
|
|
||||||
def test_do_node_deploy_maintenance(self, mock_iwdi):
|
def test_do_node_deploy_maintenance(self, mock_iwdi):
|
||||||
@ -1761,7 +1761,7 @@ class ServiceDoNodeDeployTestCase(mgr_utils.ServiceSetUpMixin,
|
|||||||
self.assertIsNone(node.last_error)
|
self.assertIsNone(node.last_error)
|
||||||
# Verify reservation has been cleared.
|
# Verify reservation has been cleared.
|
||||||
self.assertIsNone(node.reservation)
|
self.assertIsNone(node.reservation)
|
||||||
mock_iwdi.assert_called_once_with(self.context, node.instance_info)
|
self.assertFalse(mock_iwdi.called)
|
||||||
self.assertNotIn('is_whole_disk_image', node.driver_internal_info)
|
self.assertNotIn('is_whole_disk_image', node.driver_internal_info)
|
||||||
|
|
||||||
def test_do_node_deploy_rebuild_protected(self, mock_iwdi):
|
def test_do_node_deploy_rebuild_protected(self, mock_iwdi):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user