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)
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
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