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)
Exemple #2
0
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()
Exemple #3
0
    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)
Exemple #4
0
    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)
Exemple #5
0
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)
Exemple #6
0
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)