def test_use_default_value(self): # No default, no value provided, should fail instance = {} validator = util_schema.get_validator() expected_msg = '\'cmd_no_default\' is a required property' self.assertRaisesRegexp(ValidationError, expected_msg, util_schema.validate, instance=instance, schema=TEST_SCHEMA_1, cls=validator, use_default=True) # No default, value provided instance = {'cmd_no_default': 'foo'} util_schema.validate(instance=instance, schema=TEST_SCHEMA_1, cls=validator, use_default=True) # default value provided, no value, should pass instance = {} validator = util_schema.get_validator() util_schema.validate(instance=instance, schema=TEST_SCHEMA_2, cls=validator, use_default=True) # default value provided, value provided, should pass instance = {'cmd_default': 'foo'} validator = util_schema.get_validator() util_schema.validate(instance=instance, schema=TEST_SCHEMA_2, cls=validator, use_default=True)
def test_use_default_value(self): # No default, no value provided, should fail instance = {} validator = util_schema.get_validator() expected_msg = '\'arg_required_no_default\' is a required property' self.assertRaisesRegexp(ValidationError, expected_msg, util_schema.validate, instance=instance, schema=TEST_SCHEMA_1, cls=validator, use_default=True) # No default, value provided instance = {'arg_required_no_default': 'foo'} util_schema.validate(instance=instance, schema=TEST_SCHEMA_1, cls=validator, use_default=True) # default value provided, no value, should pass instance = {} validator = util_schema.get_validator() util_schema.validate(instance=instance, schema=TEST_SCHEMA_2, cls=validator, use_default=True) # default value provided, value provided, should pass instance = {'arg_required_default': 'foo'} validator = util_schema.get_validator() util_schema.validate(instance=instance, schema=TEST_SCHEMA_2, cls=validator, use_default=True)
def test_parameter_schema(self): runnertype = self._create_save_runnertype(metadata=True) saved = self._create_save_action(runnertype, metadata=True) retrieved = Action.get_by_id(saved.id) # validate generated schema schema = util_schema.get_schema_for_action_parameters(retrieved) self.assertDictEqual(schema, PARAM_SCHEMA) validator = util_schema.get_validator() validator.check_schema(schema) # use schema to validate parameters jsonschema.validate({"r2": "abc", "p1": "def"}, schema, validator) jsonschema.validate({"r2": "abc", "p1": "def", "r1": {"r1a": "ghi"}}, schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, '{"r2": "abc", "p1": "def"}', schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, {"r2": "abc"}, schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, {"r2": "abc", "p1": "def", "r1": 123}, schema, validator) # cleanup self._delete([retrieved]) try: retrieved = Action.get_by_id(saved.id) except ValueError: retrieved = None self.assertIsNone(retrieved, 'managed to retrieve after failure.')
def validate(self): # Validate policy itself cleaned = super(PolicyAPI, self).validate() # Validate policy parameters # pylint: disable=no-member policy_type_db = PolicyType.get_by_ref(cleaned.policy_type) if not policy_type_db: raise ValueError('Referenced policy_type "%s" doesnt exist' % (cleaned.policy_type)) parameters_schema = policy_type_db.parameters parameters = getattr(cleaned, 'parameters', {}) schema = util_schema.get_schema_for_resource_parameters( parameters_schema=parameters_schema) validator = util_schema.get_validator() cleaned_parameters = util_schema.validate(parameters, schema, validator, use_default=True, allow_default_none=True) cleaned.parameters = cleaned_parameters return cleaned
def test_parameter_schema(self): runnertype = self._create_save_runnertype(metadata=True) saved = self._create_save_action(runnertype, metadata=True) retrieved = Action.get_by_id(saved.id) # validate generated schema schema = util_schema.get_schema_for_action_parameters(retrieved) self.assertDictEqual(schema, PARAM_SCHEMA) validator = util_schema.get_validator() validator.check_schema(schema) # use schema to validate parameters jsonschema.validate({"r2": "abc", "p1": "def"}, schema, validator) jsonschema.validate({"r2": "abc", "p1": "def", "r1": {"r1a": "ghi"}}, schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, '{"r2": "abc", "p1": "def"}', schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, {"r2": "abc"}, schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, {"r2": "abc", "p1": "def", "r1": 123}, schema, validator) # cleanup self._delete([retrieved]) try: retrieved = Action.get_by_id(saved.id) except StackStormDBObjectNotFoundError: retrieved = None self.assertIsNone(retrieved, 'managed to retrieve after failure.')
def __init__(self, **kw): jsonschema.validate(kw, self.schema, util_schema.get_validator()) for key, value in kw.items(): setattr(self, key, value) if not hasattr(self, 'parameters'): setattr(self, 'parameters', dict()) if not hasattr(self, 'entry_point'): setattr(self, 'entry_point', '')
def test_oneof_type_allow_default_none(self): # Let validator take care of default validator = util_schema.get_validator() util_schema.validate(instance=dict(), schema=TEST_SCHEMA_5, cls=validator, use_default=True, allow_default_none=True)
def _validate_runner(runner_schema, result): LOG.debug('Validating runner output: %s', runner_schema) runner_schema = { "type": "object", "properties": runner_schema, "additionalProperties": False } schema.validate(result, runner_schema, cls=schema.get_validator('custom'))
def _validate_runner(runner_schema, result): LOG.debug("Validating runner output: %s", runner_schema) runner_schema = { "type": "object", "properties": runner_schema, "additionalProperties": False, } schema.validate(result, runner_schema, cls=schema.get_validator("custom"))
def test_allow_default_explicit_none(self): # Explicitly pass None to arguments instance = { 'arg_optional_default': None, 'arg_optional_default_none': None, 'arg_optional_no_default': None } validator = util_schema.get_validator() util_schema.validate(instance=instance, schema=TEST_SCHEMA_3, cls=validator, use_default=True, allow_default_none=True)
def _validate_action(action_schema, result, output_key): LOG.debug('Validating action output: %s', action_schema) final_result = result[output_key] action_schema = { "type": "object", "properties": action_schema, "additionalProperties": False } schema.validate(final_result, action_schema, cls=schema.get_validator('custom'))
def schedule(liveaction): """ Schedule an action to be run. :return: (liveaction, execution) :rtype: tuple """ # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. if getattr(liveaction, 'context', None) and 'parent' in liveaction.context: parent = LiveAction.get_by_id(liveaction.context['parent']) liveaction.context['user'] = getattr(parent, 'context', dict()).get('user') # Validate action. action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) if not hasattr(liveaction, 'parameters'): liveaction.parameters = dict() # Validate action parameters. schema = util_schema.get_parameter_schema(action_db) validator = util_schema.get_validator() jsonschema.validate(liveaction.parameters, schema, validator) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables] if len(overridden_immutables) > 0: raise ValueError('Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Write to database and send to message queue. liveaction.status = LIVEACTION_STATUS_SCHEDULED liveaction.start_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow()) # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) execution = executions.create_execution_object(liveaction, publish=False) # assume that this is a creation. LiveAction.publish_create(liveaction) ActionExecution.publish_create(execution) LOG.audit('Action execution scheduled. LiveAction=%s. ActionExecution=%s', liveaction, execution) return liveaction, execution
def __init__(self, **kw): # Ideally, you should not do that. You should not redefine __init__ to validate and then set # default values, instead you should define defaults in schema and use BaseAPI __init__ # validator to unwrap them. The problem here is that draft schema also contains default # values and we don't want them to be unwrapped at the same time. I've tried to remove the # default values from draft schema, but, either because of a bug or some weird intention, it # has continued to resolve $ref'erenced properties against the initial draft schema, not the # modified one jsonschema.validate(kw, self.schema, util_schema.get_validator()) for key, value in kw.items(): setattr(self, key, value) if not hasattr(self, 'runner_parameters'): setattr(self, 'runner_parameters', dict())
def _validate_action(action_schema, result, output_key): LOG.debug("Validating action output: %s", action_schema) final_result = result[output_key] action_schema = { "type": "object", "properties": action_schema, "additionalProperties": False, } schema.validate(final_result, action_schema, cls=schema.get_validator("custom"))
def validate(self): # Validate policy itself cleaned = super(PolicyAPI, self).validate() # Validate policy parameters policy_type_db = PolicyType.get_by_ref(cleaned.policy_type) if not policy_type_db: raise ValueError('Referenced policy_type "%s" doesnt exist' % (cleaned.policy_type)) parameters_schema = policy_type_db.parameters parameters = getattr(cleaned, 'parameters', {}) schema = util_schema.get_schema_for_resource_parameters( parameters_schema=parameters_schema) validator = util_schema.get_validator() cleaned_parameters = util_schema.validate(parameters, schema, validator, use_default=True, allow_default_none=True) cleaned.parameters = cleaned_parameters return cleaned
def schedule(execution): # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. if getattr(execution, 'context', None) and 'parent' in execution.context: parent = ActionExecution.get_by_id(execution.context['parent']) execution.context['user'] = getattr(parent, 'context', dict()).get('user') # Validate action. action_db = action_utils.get_action_by_ref(execution.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % execution.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % execution.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) if not hasattr(execution, 'parameters'): execution.parameters = dict() # Validate action parameters. schema = util_schema.get_parameter_schema(action_db) validator = util_schema.get_validator() jsonschema.validate(execution.parameters, schema, validator) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [p for p in six.iterkeys(execution.parameters) if p in immutables] if len(overridden_immutables) > 0: raise ValueError('Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Write to database and send to message queue. execution.status = ACTIONEXEC_STATUS_SCHEDULED execution.start_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow()) execution = ActionExecution.add_or_update(execution) LOG.audit('Action execution scheduled. ActionExecution=%s.', execution) return execution
def request(liveaction): """ Request an action execution. :return: (liveaction, execution) :rtype: tuple """ # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. if getattr(liveaction, 'context', None) and 'parent' in liveaction.context: parent_user = liveaction.context['parent'].get('user', None) if parent_user: liveaction.context['user'] = parent_user # Validate action. action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) if not hasattr(liveaction, 'parameters'): liveaction.parameters = dict() # Validate action parameters. schema = util_schema.get_parameter_schema(action_db) validator = util_schema.get_validator() util_schema.validate(liveaction.parameters, schema, validator, use_default=True) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables] if len(overridden_immutables) > 0: raise ValueError('Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if action_db.notify: liveaction.notify = action_db.notify # Write to database and send to message queue. liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction.start_timestamp = date_utils.get_datetime_utc_now() # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) # Get trace_db if it exists. This could throw. If it throws, we have to cleanup # liveaction object so we don't see things in requested mode. trace_db = None try: _, trace_db = trace_service.get_trace_db_by_live_action(liveaction) except StackStormDBObjectNotFoundError as e: _cleanup_liveaction(liveaction) raise TraceNotFoundException(str(e)) execution = executions.create_execution_object(liveaction, publish=False) if trace_db: trace_service.add_or_update_given_trace_db( trace_db=trace_db, action_executions=[str(execution.id)]) # Assume that this is a creation. LiveAction.publish_create(liveaction) LiveAction.publish_status(liveaction) ActionExecution.publish_create(execution) extra = {'liveaction_db': liveaction, 'execution_db': execution} LOG.audit('Action execution requested. LiveAction.id=%s, ActionExecution.id=%s' % (liveaction.id, execution.id), extra=extra) return liveaction, execution
import jsonschema import six from six.moves import http_client from webob import exc import pecan import pecan.jsonify import traceback from st2common.util import mongoescape as util_mongodb from st2common.util import schema as util_schema from st2common.util.jsonify import json_encode from st2common import log as logging LOG = logging.getLogger(__name__) VALIDATOR = util_schema.get_validator(assign_property_default=False) @six.add_metaclass(abc.ABCMeta) class BaseAPI(object): schema = abc.abstractproperty def __init__(self, **kw): for key, value in kw.items(): setattr(self, key, value) def __repr__(self): name = type(self).__name__ attrs = ', '.join("'%s':%r" % item for item in six.iteritems(vars(self))) # The format here is so that eval can be applied.
def create_request(liveaction, action_db=None, runnertype_db=None): """ Create an action execution. :param action_db: Action model to operate one. If not provided, one is retrieved from the database using values from "liveaction". :type action_db: :class:`ActionDB` :param runnertype_db: Runner model to operate one. If not provided, one is retrieved from the database using values from "liveaction". :type runnertype_db: :class:`RunnerTypeDB` :return: (liveaction, execution) :rtype: tuple """ # We import this here to avoid conflicts w/ runners that might import this # file since the runners don't have the config context by default. from st2common.metrics.base import get_driver # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. parent_context = executions.get_parent_context(liveaction) or {} parent_user = parent_context.get('user', None) if parent_user: liveaction.context['user'] = parent_user # Validate action if not action_db: action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) if not runnertype_db: runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) if not hasattr(liveaction, 'parameters'): liveaction.parameters = dict() # For consistency add pack to the context here in addition to RunnerContainer.dispatch() method liveaction.context['pack'] = action_db.pack # Validate action parameters. schema = util_schema.get_schema_for_action_parameters(action_db, runnertype_db) validator = util_schema.get_validator() util_schema.validate(liveaction.parameters, schema, validator, use_default=True, allow_default_none=True) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables] if len(overridden_immutables) > 0: raise ValueError('Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if not _is_notify_empty(action_db.notify): liveaction.notify = action_db.notify # Write to database and send to message queue. liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction.start_timestamp = date_utils.get_datetime_utc_now() # Set the "action_is_workflow" attribute liveaction.action_is_workflow = action_db.is_workflow() # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) # Get trace_db if it exists. This could throw. If it throws, we have to cleanup # liveaction object so we don't see things in requested mode. trace_db = None try: _, trace_db = trace_service.get_trace_db_by_live_action(liveaction) except db_exc.StackStormDBObjectNotFoundError as e: _cleanup_liveaction(liveaction) raise trace_exc.TraceNotFoundException(six.text_type(e)) execution = executions.create_execution_object(liveaction=liveaction, action_db=action_db, runnertype_db=runnertype_db, publish=False) if trace_db: trace_service.add_or_update_given_trace_db( trace_db=trace_db, action_executions=[ trace_service.get_trace_component_for_action_execution(execution, liveaction) ]) get_driver().inc_counter('action.executions.%s' % (liveaction.status)) return liveaction, execution
def request(liveaction): """ Request an action execution. :return: (liveaction, execution) :rtype: tuple """ # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. if getattr(liveaction, "context", None) and "parent" in liveaction.context: parent_user = liveaction.context["parent"].get("user", None) if parent_user: liveaction.context["user"] = parent_user # Validate action. action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type["name"]) if not hasattr(liveaction, "parameters"): liveaction.parameters = dict() # Validate action parameters. schema = util_schema.get_parameter_schema(action_db) validator = util_schema.get_validator() util_schema.validate(liveaction.parameters, schema, validator, use_default=True) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables] if len(overridden_immutables) > 0: raise ValueError("Override of immutable parameter(s) %s is unsupported." % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if action_db.notify: liveaction.notify = action_db.notify # Write to database and send to message queue. liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction.start_timestamp = date_utils.get_datetime_utc_now() # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) execution = executions.create_execution_object(liveaction, publish=False) # Assume that this is a creation. LiveAction.publish_create(liveaction) LiveAction.publish_status(liveaction) ActionExecution.publish_create(execution) extra = {"liveaction_db": liveaction, "execution_db": execution} LOG.audit( "Action execution requested. LiveAction.id=%s, ActionExecution.id=%s" % (liveaction.id, execution.id), extra=extra, ) return liveaction, execution
def request(liveaction): """ Request an action execution. :return: (liveaction, execution) :rtype: tuple """ # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. if getattr(liveaction, 'context', None) and 'parent' in liveaction.context: parent = LiveAction.get_by_id(liveaction.context['parent']) liveaction.context['user'] = getattr(parent, 'context', dict()).get('user') # Validate action. action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) if not hasattr(liveaction, 'parameters'): liveaction.parameters = dict() # Validate action parameters. schema = util_schema.get_parameter_schema(action_db) validator = util_schema.get_validator() util_schema.validate(liveaction.parameters, schema, validator, use_default=True) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [ p for p in six.iterkeys(liveaction.parameters) if p in immutables ] if len(overridden_immutables) > 0: raise ValueError( 'Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if action_db.notify: liveaction.notify = action_db.notify # Write to database and send to message queue. liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction.start_timestamp = date_utils.get_datetime_utc_now() # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) execution = executions.create_execution_object(liveaction, publish=False) # Assume that this is a creation. LiveAction.publish_create(liveaction) LiveAction.publish_status(liveaction) ActionExecution.publish_create(execution) extra = {'liveaction_db': liveaction, 'execution_db': execution} LOG.audit( 'Action execution requested. LiveAction.id=%s, ActionExecution.id=%s' % (liveaction.id, execution.id), extra=extra) return liveaction, execution
def create_request(liveaction): """ Create an action execution. :return: (liveaction, execution) :rtype: tuple """ # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. parent_context = executions.get_parent_context(liveaction) if parent_context: parent_user = parent_context.get('user', None) if parent_user: liveaction.context['user'] = parent_user # Validate action. action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) if not hasattr(liveaction, 'parameters'): liveaction.parameters = dict() # Validate action parameters. schema = util_schema.get_schema_for_action_parameters(action_db) validator = util_schema.get_validator() util_schema.validate(liveaction.parameters, schema, validator, use_default=True, allow_default_none=True) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [ p for p in six.iterkeys(liveaction.parameters) if p in immutables ] if len(overridden_immutables) > 0: raise ValueError( 'Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if not _is_notify_empty(action_db.notify): liveaction.notify = action_db.notify # Write to database and send to message queue. liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction.start_timestamp = date_utils.get_datetime_utc_now() # Set the "action_is_workflow" attribute liveaction.action_is_workflow = action_db.is_workflow() # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) # Get trace_db if it exists. This could throw. If it throws, we have to cleanup # liveaction object so we don't see things in requested mode. trace_db = None try: _, trace_db = trace_service.get_trace_db_by_live_action(liveaction) except db_exc.StackStormDBObjectNotFoundError as e: _cleanup_liveaction(liveaction) raise trace_exc.TraceNotFoundException(str(e)) execution = executions.create_execution_object(liveaction, publish=False) if trace_db: trace_service.add_or_update_given_trace_db( trace_db=trace_db, action_executions=[ trace_service.get_trace_component_for_action_execution( execution, liveaction) ]) return liveaction, execution
def schedule(liveaction): """ Schedule an action to be run. :return: (liveaction, execution) :rtype: tuple """ # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. if getattr(liveaction, 'context', None) and 'parent' in liveaction.context: parent = LiveAction.get_by_id(liveaction.context['parent']) liveaction.context['user'] = getattr(parent, 'context', dict()).get('user') # Validate action. action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) if not hasattr(liveaction, 'parameters'): liveaction.parameters = dict() # Validate action parameters. schema = util_schema.get_parameter_schema(action_db) validator = util_schema.get_validator() util_schema.validate(liveaction.parameters, schema, validator, use_default=True) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables] if len(overridden_immutables) > 0: raise ValueError('Override of immutable parameter(s) %s is unsupported.' % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if action_db.notify: liveaction.notify = action_db.notify else: print(action_db) # Write to database and send to message queue. liveaction.status = LIVEACTION_STATUS_SCHEDULED liveaction.start_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow()) # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) execution = executions.create_execution_object(liveaction, publish=False) # assume that this is a creation. LiveAction.publish_create(liveaction) ActionExecution.publish_create(execution) extra = {'liveaction_db': liveaction, 'execution_db': execution} LOG.audit('Action execution scheduled. LiveAction.id=%s, ActionExecution.id=%s' % (liveaction.id, execution.id), extra=extra) return liveaction, execution
import jsonschema import six from six.moves import http_client from webob import exc import pecan import pecan.jsonify from st2common.util import mongoescape as util_mongodb from st2common.util import schema as util_schema from st2common.util.jsonify import json_encode from st2common import log as logging from st2common.constants.auth import QUERY_PARAM_ATTRIBUTE_NAME LOG = logging.getLogger(__name__) VALIDATOR = util_schema.get_validator(assign_property_default=False) # A list of method names for which we don't want to log the result / response RESPONSE_LOGGING_METHOD_NAME_BLACKLIST = ['get_all'] # A list of controller classes for which we don't want to log the result / response RESPONSE_LOGGING_CONTROLLER_NAME_BLACKLIST = [ 'ActionExecutionChildrenController', # action executions can be big 'ActionExecutionAttributeController', # result can be big 'ActionExecutionsController' # action executions can be big ] @six.add_metaclass(abc.ABCMeta) class BaseAPI(object): schema = abc.abstractproperty
def create_request(liveaction, action_db=None, runnertype_db=None): """ Create an action execution. :param action_db: Action model to operate one. If not provided, one is retrieved from the database using values from "liveaction". :type action_db: :class:`ActionDB` :param runnertype_db: Runner model to operate one. If not provided, one is retrieved from the database using values from "liveaction". :type runnertype_db: :class:`RunnerTypeDB` :return: (liveaction, execution) :rtype: tuple """ # We import this here to avoid conflicts w/ runners that might import this # file since the runners don't have the config context by default. from st2common.metrics.base import get_driver # Use the user context from the parent action execution. Subtasks in a workflow # action can be invoked by a system user and so we want to use the user context # from the original workflow action. parent_context = executions.get_parent_context(liveaction) or {} parent_user = parent_context.get("user", None) if parent_user: liveaction.context["user"] = parent_user # Validate action if not action_db: action_db = action_utils.get_action_by_ref(liveaction.action) if not action_db: raise ValueError('Action "%s" cannot be found.' % liveaction.action) if not action_db.enabled: raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action) if not runnertype_db: runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type["name"]) if not hasattr(liveaction, "parameters"): liveaction.parameters = dict() # For consistency add pack to the context here in addition to RunnerContainer.dispatch() method liveaction.context["pack"] = action_db.pack # Validate action parameters. schema = util_schema.get_schema_for_action_parameters( action_db, runnertype_db) validator = util_schema.get_validator() util_schema.validate( liveaction.parameters, schema, validator, use_default=True, allow_default_none=True, ) # validate that no immutable params are being overriden. Although possible to # ignore the override it is safer to inform the user to avoid surprises. immutables = _get_immutable_params(action_db.parameters) immutables.extend(_get_immutable_params(runnertype_db.runner_parameters)) overridden_immutables = [ p for p in six.iterkeys(liveaction.parameters) if p in immutables ] if len(overridden_immutables) > 0: raise ValueError( "Override of immutable parameter(s) %s is unsupported." % str(overridden_immutables)) # Set notification settings for action. # XXX: There are cases when we don't want notifications to be sent for a particular # execution. So we should look at liveaction.parameters['notify'] # and not set liveaction.notify. if not _is_notify_skipped(liveaction) and not _is_notify_empty( action_db.notify): liveaction.notify = action_db.notify # Write to database and send to message queue. liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED liveaction.start_timestamp = date_utils.get_datetime_utc_now() # Set the "action_is_workflow" attribute liveaction.action_is_workflow = action_db.is_workflow() # Publish creation after both liveaction and actionexecution are created. liveaction = LiveAction.add_or_update(liveaction, publish=False) # Get trace_db if it exists. This could throw. If it throws, we have to cleanup # liveaction object so we don't see things in requested mode. trace_db = None try: _, trace_db = trace_service.get_trace_db_by_live_action(liveaction) except db_exc.StackStormDBObjectNotFoundError as e: _cleanup_liveaction(liveaction) raise trace_exc.TraceNotFoundException(six.text_type(e)) execution = executions.create_execution_object( liveaction=liveaction, action_db=action_db, runnertype_db=runnertype_db, publish=False, ) if trace_db: trace_service.add_or_update_given_trace_db( trace_db=trace_db, action_executions=[ trace_service.get_trace_component_for_action_execution( execution, liveaction) ], ) get_driver().inc_counter("action.executions.%s" % (liveaction.status)) return liveaction, execution