Get rid of set_failed_state duplication

drivers.modules.agent and drivers.modules.iscsi_deploy contain
_set_failed_state and set_failed_state functions respectively, which
are almost identical. This change moves this functionality to
drivers.modules.deploy_utils.

Change-Id: I2987898e656b2451d3eacd0d5e9bc7fa35723ad5
This commit is contained in:
Vladyslav Drok
2014-12-12 17:19:35 +02:00
parent 2db2659a42
commit 80670140b1
6 changed files with 40 additions and 65 deletions

View File

@@ -114,34 +114,6 @@ def _get_tftp_image_info(node):
return pxe_utils.get_deploy_kr_info(node.uuid, node.driver_info)
def _set_failed_state(task, msg):
"""Set a node's error state and provision state to signal Nova.
When deploy steps aren't called by explicitly the conductor, but are
the result of callbacks, we need to set the node's state explicitly.
This tells Nova to change the instance's status so the user can see
their deploy/tear down had an issue and makes debugging/deleting Nova
instances easier.
"""
node = task.node
node.provision_state = states.DEPLOYFAIL
node.target_provision_state = states.NOSTATE
node.save()
try:
manager_utils.node_power_action(task, states.POWER_OFF)
except Exception:
msg = (_('Node %s failed to power off while handling deploy '
'failure. This may be a serious condition. Node '
'should be removed from Ironic or put in maintenance '
'mode until the problem is resolved.') % node.uuid)
LOG.error(msg)
finally:
# NOTE(deva): node_power_action() erases node.last_error
# so we need to set it again here.
node.last_error = msg
node.save()
@image_cache.cleanup(priority=25)
class AgentTFTPImageCache(image_cache.ImageCache):
def __init__(self, image_service=None):
@@ -388,7 +360,7 @@ class AgentVendorInterface(base.VendorInterface):
LOG.exception(_LE('Async exception for %(node)s: %(msg)s'),
{'node': node,
'msg': msg})
_set_failed_state(task, msg)
deploy_utils.set_failed_state(task, msg)
def _deploy_is_done(self, node):
return self._client.deploy_is_done(node)
@@ -438,7 +410,7 @@ class AgentVendorInterface(base.VendorInterface):
msg = _('node %(node)s command status errored: %(error)s') % (
{'node': node.uuid, 'error': error})
LOG.error(msg)
_set_failed_state(task, msg)
deploy_utils.set_failed_state(task, msg)
return
LOG.debug('Rebooting node %s to disk', node.uuid)

View File

@@ -29,7 +29,9 @@ from ironic.common import exception
from ironic.common.i18n import _
from ironic.common.i18n import _LE
from ironic.common import images
from ironic.common import states
from ironic.common import utils
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import image_cache
from ironic.openstack.common import log as logging
@@ -441,3 +443,32 @@ def fetch_images(ctx, cache, images_info, force_raw=True):
# (probably unrelated) processes
for href, path in images_info:
cache.fetch_image(href, path, ctx=ctx, force_raw=force_raw)
def set_failed_state(task, msg):
"""Sets the deploy status as failed with relevant messages.
This method sets the deployment as fail with the given message.
It sets node's provision_state to DEPLOYFAIL and updates last_error
with the given error message. It also powers off the baremetal node.
:param task: a TaskManager instance containing the node to act on.
:param msg: the message to set in last_error of the node.
"""
node = task.node
node.provision_state = states.DEPLOYFAIL
node.target_provision_state = states.NOSTATE
node.save()
try:
manager_utils.node_power_action(task, states.POWER_OFF)
except Exception:
msg2 = (_LE('Node %s failed to power off while handling deploy '
'failure. This may be a serious condition. Node '
'should be removed from Ironic or put in maintenance '
'mode until the problem is resolved.') % node.uuid)
LOG.exception(msg2)
finally:
# NOTE(deva): node_power_action() erases node.last_error
# so we need to set it again here.
node.last_error = msg
node.save()

View File

@@ -550,4 +550,4 @@ class VendorPassthru(base.VendorInterface):
'Error: %(error)s'),
{'instance': node.instance_uuid, 'error': e})
msg = _('Failed to continue iSCSI deployment.')
iscsi_deploy.set_failed_state(task, msg)
deploy_utils.set_failed_state(task, msg)

View File

@@ -26,7 +26,6 @@ from ironic.common import image_service as service
from ironic.common import keystone
from ironic.common import states
from ironic.common import utils
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import image_cache
from ironic.drivers import utils as driver_utils
@@ -243,35 +242,6 @@ def get_deploy_info(node, **kwargs):
return params
def set_failed_state(task, msg):
"""Sets the deploy status as failed with relevant messages.
This method sets the deployment as fail with the given message.
It sets node's provision_state to DEPLOYFAIL and updates last_error
with the given error message. It also powers off the baremetal node.
:param task: a TaskManager instance containing the node to act on.
:param msg: the message to set in last_error of the node.
"""
node = task.node
node.provision_state = states.DEPLOYFAIL
node.target_provision_state = states.NOSTATE
node.save()
try:
manager_utils.node_power_action(task, states.POWER_OFF)
except Exception:
msg2 = (_('Node %s failed to power off while handling deploy '
'failure. This may be a serious condition. Node '
'should be removed from Ironic or put in maintenance '
'mode until the problem is resolved.') % node.uuid)
LOG.exception(msg2)
finally:
# NOTE(deva): node_power_action() erases node.last_error
# so we need to set it again here.
node.last_error = msg
node.save()
def continue_deploy(task, **kwargs):
"""Resume a deployment upon getting POST data from deploy ramdisk.
@@ -293,7 +263,7 @@ def continue_deploy(task, **kwargs):
if ramdisk_error:
LOG.error(_LE('Error returned from deploy ramdisk: %s'),
ramdisk_error)
set_failed_state(task, _('Failure in deploy ramdisk.'))
deploy_utils.set_failed_state(task, _('Failure in deploy ramdisk.'))
destroy_images(node.uuid)
return
@@ -307,7 +277,8 @@ def continue_deploy(task, **kwargs):
LOG.error(_LE('Deploy failed for instance %(instance)s. '
'Error: %(error)s'),
{'instance': node.instance_uuid, 'error': e})
set_failed_state(task, _('Failed to continue iSCSI deployment.'))
deploy_utils.set_failed_state(task, _('Failed to continue '
'iSCSI deployment.'))
destroy_images(node.uuid)
return root_uuid

View File

@@ -487,4 +487,4 @@ class VendorPassthru(base.VendorInterface):
'Error: %(error)s'),
{'instance': node.instance_uuid, 'error': e})
msg = _('Failed to continue iSCSI deployment.')
iscsi_deploy.set_failed_state(task, msg)
deploy_utils.set_failed_state(task, msg)

View File

@@ -22,6 +22,7 @@ from ironic.common import pxe_utils
from ironic.common import states
from ironic.conductor import task_manager
from ironic.drivers.modules import agent
from ironic.drivers.modules import deploy_utils
from ironic import objects
from ironic.tests.conductor import utils as mgr_utils
from ironic.tests.db import base as db_base
@@ -388,7 +389,7 @@ class TestAgentVendor(db_base.DbTestCase):
self.assertRaises(exception.MissingParameterValue,
self.passthru.heartbeat, task, **kwargs)
@mock.patch.object(agent, '_set_failed_state')
@mock.patch.object(deploy_utils, 'set_failed_state')
@mock.patch.object(agent.AgentVendorInterface, '_deploy_is_done')
def test_heartbeat_deploy_done_fails(self, done_mock, failed_mock):
kwargs = {