def continue_node_deploy(task): """Continue deployment after finishing an async deploy step. This function calculates which step has to run next and passes control into do_next_deploy_step. On the first run, deploy steps and templates are also validated. :param task: a TaskManager instance with an exclusive lock """ node = task.node # Agent is now running, we're ready to validate the remaining steps if not node.driver_internal_info.get('steps_validated'): try: conductor_steps.validate_deploy_templates(task) conductor_steps.set_node_deployment_steps(task, reset_current=False) except exception.IronicException as exc: msg = _('Failed to validate the final deploy steps list ' 'for node %(node)s: %(exc)s') % { 'node': node.uuid, 'exc': exc } return utils.deploying_error_handler(task, msg) info = node.driver_internal_info info['steps_validated'] = True node.driver_internal_info = info node.save() next_step_index = utils.update_next_step_index(task, 'deploy') do_next_deploy_step(task, next_step_index)
def validate_deploy_steps(task): """Validate the deploy steps after the ramdisk learns about them.""" conductor_steps.validate_user_deploy_steps_and_templates(task) conductor_steps.set_node_deployment_steps(task, reset_current=False) info = task.node.driver_internal_info info['steps_validated'] = True task.node.driver_internal_info = info task.node.save()
def test_set_node_deployment_steps_skip_missing(self, mock_steps): mock_steps.return_value = self.deploy_steps with task_manager.acquire(self.context, self.node.uuid, shared=False) as task: conductor_steps.set_node_deployment_steps(task, skip_missing=True) self.node.refresh() self.assertEqual(self.deploy_steps, self.node.driver_internal_info['deploy_steps']) self.assertEqual({}, self.node.deploy_step) self.assertIsNone( self.node.driver_internal_info['deploy_step_index']) mock_steps.assert_called_once_with(task, skip_missing=True)
def test_set_node_deployment_steps(self, mock_steps): mock_steps.return_value = self.deploy_steps with task_manager.acquire( self.context, self.node.uuid, shared=False) as task: conductor_steps.set_node_deployment_steps(task) self.node.refresh() self.assertEqual(self.deploy_steps, self.node.driver_internal_info['deploy_steps']) self.assertEqual({}, self.node.deploy_step) self.assertIsNone( self.node.driver_internal_info['deploy_step_index']) mock_steps.assert_called_once_with(task)
def do_node_deploy(task, conductor_id=None, configdrive=None): """Prepare the environment and deploy a node.""" node = task.node utils.del_secret_token(node) try: if configdrive: if isinstance(configdrive, dict): configdrive = utils.build_configdrive(node, configdrive) _store_configdrive(node, configdrive) except (exception.SwiftOperationError, exception.ConfigInvalid) as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Error while uploading the configdrive for %(node)s ' 'to Swift') % {'node': node.uuid}, _('Failed to upload the configdrive to Swift. ' 'Error: %s') % e, clean_up=False) except db_exception.DBDataError as e: with excutils.save_and_reraise_exception(): # NOTE(hshiina): This error happens when the configdrive is # too large. Remove the configdrive from the # object to update DB successfully in handling # the failure. node.obj_reset_changes() utils.deploying_error_handler( task, ('Error while storing the configdrive for %(node)s into ' 'the database: %(err)s') % { 'node': node.uuid, 'err': e }, _("Failed to store the configdrive in the database. " "%s") % e, clean_up=False) except Exception as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Unexpected error while preparing the configdrive for ' 'node %(node)s') % {'node': node.uuid}, _("Failed to prepare the configdrive. Exception: %s") % e, traceback=True, clean_up=False) try: task.driver.deploy.prepare(task) except exception.IronicException as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Error while preparing to deploy to node %(node)s: ' '%(err)s') % { 'node': node.uuid, 'err': e }, _("Failed to prepare to deploy: %s") % e, clean_up=False) except Exception as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Unexpected error while preparing to deploy to node ' '%(node)s') % {'node': node.uuid}, _("Failed to prepare to deploy. Exception: %s") % e, traceback=True, clean_up=False) try: # This gets the deploy steps and puts them in the node's # driver_internal_info['deploy_steps']. conductor_steps.set_node_deployment_steps(task) except exception.InstanceDeployFailure as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, 'Error while getting deploy steps; cannot deploy to node ' '%(node)s. Error: %(err)s' % { 'node': node.uuid, 'err': e }, _("Cannot get deploy steps; failed to deploy: %s") % e) if not node.driver_internal_info.get('deploy_steps'): msg = _('Error while getting deploy steps: no steps returned for ' 'node %s') % node.uuid utils.deploying_error_handler( task, msg, _("No deploy steps returned by the driver")) raise exception.InstanceDeployFailure(msg) do_next_deploy_step(task, 0, conductor_id)
def do_node_deploy(task, conductor_id=None, configdrive=None, deploy_steps=None): """Prepare the environment and deploy a node.""" node = task.node utils.wipe_deploy_internal_info(task) try: if configdrive: if isinstance(configdrive, dict): configdrive = utils.build_configdrive(node, configdrive) _store_configdrive(node, configdrive) except (exception.SwiftOperationError, exception.ConfigInvalid) as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Error while uploading the configdrive for %(node)s ' 'to Swift') % {'node': node.uuid}, _('Failed to upload the configdrive to Swift. ' 'Error: %s') % e, clean_up=False) except db_exception.DBDataError as e: with excutils.save_and_reraise_exception(): # NOTE(hshiina): This error happens when the configdrive is # too large. Remove the configdrive from the # object to update DB successfully in handling # the failure. node.obj_reset_changes() utils.deploying_error_handler( task, ('Error while storing the configdrive for %(node)s into ' 'the database: %(err)s') % { 'node': node.uuid, 'err': e }, _("Failed to store the configdrive in the database. " "%s") % e, clean_up=False) except Exception as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Unexpected error while preparing the configdrive for ' 'node %(node)s') % {'node': node.uuid}, _("Failed to prepare the configdrive. Exception: %s") % e, traceback=True, clean_up=False) try: task.driver.deploy.prepare(task) except exception.IronicException as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Error while preparing to deploy to node %(node)s: ' '%(err)s') % { 'node': node.uuid, 'err': e }, _("Failed to prepare to deploy: %s") % e, clean_up=False) except Exception as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, ('Unexpected error while preparing to deploy to node ' '%(node)s') % {'node': node.uuid}, _("Failed to prepare to deploy. Exception: %s") % e, traceback=True, clean_up=False) try: # If any deploy steps provided by user, save them to node. They will be # validated & processed later together with driver and deploy template # steps. if deploy_steps: info = node.driver_internal_info info['user_deploy_steps'] = deploy_steps node.driver_internal_info = info node.save() # This gets the deploy steps (if any) from driver, deploy template and # deploy_steps argument and updates them in the node's # driver_internal_info['deploy_steps']. In-band steps are skipped since # we know that an agent is not running yet. conductor_steps.set_node_deployment_steps(task, skip_missing=True) except exception.InstanceDeployFailure as e: with excutils.save_and_reraise_exception(): utils.deploying_error_handler( task, 'Error while getting deploy steps; cannot deploy to node ' '%(node)s. Error: %(err)s' % { 'node': node.uuid, 'err': e }, _("Cannot get deploy steps; failed to deploy: %s") % e) if not node.driver_internal_info.get('deploy_steps'): msg = _('Error while getting deploy steps: no steps returned for ' 'node %s') % node.uuid utils.deploying_error_handler( task, msg, _("No deploy steps returned by the driver")) raise exception.InstanceDeployFailure(msg) if conductor_id is not None: # Update conductor_affinity to reference this conductor's ID # since there may be local persistent state node.conductor_affinity = conductor_id node.save() do_next_deploy_step(task, 0)