def test_valid_schema(self):
        result, status = output_schema.validate_output(
            copy.deepcopy(RUNNER_SCHEMA),
            copy.deepcopy(ACTION_SCHEMA),
            copy.deepcopy(ACTION_RESULT),
            LIVEACTION_STATUS_SUCCEEDED,
            OUTPUT_KEY,
        )

        self.assertEqual(result, ACTION_RESULT)
        self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED)
    def test_valid_schema(self):
        result, status = output_schema.validate_output(
            copy.deepcopy(RUNNER_SCHEMA),
            copy.deepcopy(ACTION_SCHEMA),
            copy.deepcopy(ACTION_RESULT),
            LIVEACTION_STATUS_SUCCEEDED,
            OUTPUT_KEY,
        )

        self.assertEqual(result, ACTION_RESULT)
        self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED)
    def test_invalid_action_schema(self):
        result, status = output_schema.validate_output(
            copy.deepcopy(RUNNER_SCHEMA),
            copy.deepcopy(ACTION_SCHEMA_FAIL),
            copy.deepcopy(ACTION_RESULT),
            LIVEACTION_STATUS_SUCCEEDED,
            OUTPUT_KEY,
        )

        expected_result = {
            'error': "Additional properties are not allowed",
            'message': u'Error validating output. See error output for more details.'
        }

        # To avoid random failures (especially in python3) this assert cant be
        # exact since the parameters can be ordered differently per execution.
        self.assertIn(expected_result['error'], result['error'])
        self.assertEqual(result['message'], expected_result['message'])
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
    def test_invalid_action_schema(self):
        result, status = output_schema.validate_output(
            copy.deepcopy(RUNNER_SCHEMA),
            copy.deepcopy(ACTION_SCHEMA_FAIL),
            copy.deepcopy(ACTION_RESULT),
            LIVEACTION_STATUS_SUCCEEDED,
            OUTPUT_KEY,
        )

        expected_result = {
            "error":
            "Additional properties are not allowed",
            "message":
            "Error validating output. See error output for more details.",
        }

        # To avoid random failures (especially in python3) this assert cant be
        # exact since the parameters can be ordered differently per execution.
        self.assertIn(expected_result["error"], result["error"])
        self.assertEqual(result["message"], expected_result["message"])
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
    def test_invalid_runner_schema(self):
        result, status = output_schema.validate_output(
            copy.deepcopy(RUNNER_SCHEMA_FAIL),
            copy.deepcopy(ACTION_SCHEMA),
            copy.deepcopy(ACTION_RESULT),
            LIVEACTION_STATUS_SUCCEEDED,
            OUTPUT_KEY,
        )

        expected_result = {
            "error":
            ("Additional properties are not allowed ('output' was unexpected)"
             "\n\nFailed validating 'additionalProperties' in schema:\n    {'addi"
             "tionalProperties': False,\n     'properties': {'not_a_key_you_have': "
             "{'type': 'string'}},\n     'type': 'object'}\n\nOn instance:\n    {'"
             "output': {'deep_output': {'deep_item_1': 'Jindal'},\n                "
             "'output_1': 'Bobby',\n                'output_2': 5}}"),
            "message":
            "Error validating output. See error output for more details.",
        }

        self.assertEqual(result, expected_result)
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
    def test_invalid_runner_schema(self):
        result, status = output_schema.validate_output(
            copy.deepcopy(RUNNER_SCHEMA_FAIL),
            copy.deepcopy(ACTION_SCHEMA),
            copy.deepcopy(ACTION_RESULT),
            LIVEACTION_STATUS_SUCCEEDED,
            OUTPUT_KEY,
        )

        expected_result = {
            'error': (
                "Additional properties are not allowed ('output' was unexpected)"
                "\n\nFailed validating 'additionalProperties' in schema:\n    {'addi"
                "tionalProperties': False,\n     'properties': {'not_a_key_you_have': "
                "{'type': 'string'}},\n     'type': 'object'}\n\nOn instance:\n    {'"
                "output': {'deep_output': {'deep_item_1': 'Jindal'},\n                "
                "'output_1': 'Bobby',\n                'output_2': 5}}"
            ),
            'message': 'Error validating output. See error output for more details.'
        }

        self.assertEqual(result, expected_result)
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
Example #7
0
def update_liveaction_status(
    status=None,
    result=None,
    context=None,
    end_timestamp=None,
    liveaction_id=None,
    runner_info=None,
    liveaction_db=None,
    publish=True,
):
    """
    Update the status of the specified LiveAction to the value provided in
    new_status.

    The LiveAction may be specified using either liveaction_id, or as an
    liveaction_db instance.
    """

    if (liveaction_id is None) and (liveaction_db is None):
        raise ValueError(
            "Must specify an liveaction_id or an liveaction_db when "
            "calling update_LiveAction_status"
        )

    if liveaction_db is None:
        liveaction_db = get_liveaction_by_id(liveaction_id)

    if status not in LIVEACTION_STATUSES:
        raise ValueError(
            'Attempting to set status for LiveAction "%s" '
            'to unknown status string. Unknown status is "%s"' % (liveaction_db, status)
        )

    if (
        result
        and cfg.CONF.system.validate_output_schema
        and status == LIVEACTION_STATUS_SUCCEEDED
    ):
        action_db = get_action_by_ref(liveaction_db.action)
        runner_db = get_runnertype_by_name(action_db.runner_type["name"])
        result, status = output_schema.validate_output(
            runner_db.output_schema,
            action_db.output_schema,
            result,
            status,
            runner_db.output_key,
        )

    # If liveaction_db status is set then we need to decrement the counter
    # because it is transitioning to a new state
    if liveaction_db.status:
        get_driver().dec_counter("action.executions.%s" % (liveaction_db.status))

    # If status is provided then we need to increment the timer because the action
    # is transitioning into this new state
    if status:
        get_driver().inc_counter("action.executions.%s" % (status))

    extra = {"liveaction_db": liveaction_db}
    LOG.debug(
        'Updating ActionExection: "%s" with status="%s"',
        liveaction_db.id,
        status,
        extra=extra,
    )

    # If liveaction is already canceled, then do not allow status to be updated.
    if (
        liveaction_db.status == LIVEACTION_STATUS_CANCELED
        and status != LIVEACTION_STATUS_CANCELED
    ):
        LOG.info(
            'Unable to update ActionExecution "%s" with status="%s". '
            "ActionExecution is already canceled.",
            liveaction_db.id,
            status,
            extra=extra,
        )
        return liveaction_db

    old_status = liveaction_db.status
    liveaction_db.status = status

    if result:
        liveaction_db.result = result

    if context:
        liveaction_db.context.update(context)

    if end_timestamp:
        liveaction_db.end_timestamp = end_timestamp

    if runner_info:
        liveaction_db.runner_info = runner_info

    # TODO: This is not efficient. Perform direct partial update and only update
    # manipulated fields
    liveaction_db = LiveAction.add_or_update(liveaction_db)

    LOG.debug("Updated status for LiveAction object.", extra=extra)

    if publish and status != old_status:
        LiveAction.publish_status(liveaction_db)
        LOG.debug("Published status for LiveAction object.", extra=extra)

    return liveaction_db
Example #8
0
def update_liveaction_status(status=None, result=None, context=None, end_timestamp=None,
                             liveaction_id=None, runner_info=None, liveaction_db=None,
                             publish=True):
    """
        Update the status of the specified LiveAction to the value provided in
        new_status.

        The LiveAction may be specified using either liveaction_id, or as an
        liveaction_db instance.
    """

    if (liveaction_id is None) and (liveaction_db is None):
        raise ValueError('Must specify an liveaction_id or an liveaction_db when '
                         'calling update_LiveAction_status')

    if liveaction_db is None:
        liveaction_db = get_liveaction_by_id(liveaction_id)

    if status not in LIVEACTION_STATUSES:
        raise ValueError('Attempting to set status for LiveAction "%s" '
                         'to unknown status string. Unknown status is "%s"'
                         % (liveaction_db, status))

    if result and cfg.CONF.system.validate_output_schema and status == LIVEACTION_STATUS_SUCCEEDED:
        action_db = get_action_by_ref(liveaction_db.action)
        runner_db = get_runnertype_by_name(action_db.runner_type['name'])
        result, status = output_schema.validate_output(
            runner_db.output_schema,
            action_db.output_schema,
            result,
            status,
            runner_db.output_key,
        )

    # If liveaction_db status is set then we need to decrement the counter
    # because it is transitioning to a new state
    if liveaction_db.status:
        get_driver().dec_counter('action.executions.%s' % (liveaction_db.status))

    # If status is provided then we need to increment the timer because the action
    # is transitioning into this new state
    if status:
        get_driver().inc_counter('action.executions.%s' % (status))

    extra = {'liveaction_db': liveaction_db}
    LOG.debug('Updating ActionExection: "%s" with status="%s"', liveaction_db.id, status,
              extra=extra)

    # If liveaction is already canceled, then do not allow status to be updated.
    if liveaction_db.status == LIVEACTION_STATUS_CANCELED and status != LIVEACTION_STATUS_CANCELED:
        LOG.info('Unable to update ActionExecution "%s" with status="%s". '
                 'ActionExecution is already canceled.', liveaction_db.id, status, extra=extra)
        return liveaction_db

    old_status = liveaction_db.status
    liveaction_db.status = status

    if result:
        liveaction_db.result = result

    if context:
        liveaction_db.context.update(context)

    if end_timestamp:
        liveaction_db.end_timestamp = end_timestamp

    if runner_info:
        liveaction_db.runner_info = runner_info

    # TODO: This is not efficient. Perform direct partial update and only update
    # manipulated fields
    liveaction_db = LiveAction.add_or_update(liveaction_db)

    LOG.debug('Updated status for LiveAction object.', extra=extra)

    if publish and status != old_status:
        LiveAction.publish_status(liveaction_db)
        LOG.debug('Published status for LiveAction object.', extra=extra)

    return liveaction_db