class RunnerTypeAPI(BaseAPI): """ The representation of an RunnerType in the system. An RunnerType has a one-to-one mapping to a particular ActionRunner implementation. """ model = RunnerTypeDB schema = { "title": "Runner", "description": "A handler for a specific type of actions.", "type": "object", "properties": { "id": { "description": "The unique identifier for the action runner.", "type": "string", "default": None }, "uid": { "type": "string" }, "name": { "description": "The name of the action runner.", "type": "string", "required": True }, "description": { "description": "The description of the action runner.", "type": "string" }, "enabled": { "description": "Enable or disable the action runner.", "type": "boolean", "default": True }, "runner_package": { "description": "The python package that implements the " "action runner for this type.", "type": "string", "required": False }, "runner_module": { "description": "The python module that implements the " "action runner for this type.", "type": "string", "required": True }, "query_module": { "description": "The python module that implements the " "results tracker (querier) for the runner.", "type": "string", "required": False }, "runner_parameters": { "description": "Input parameters for the action runner.", "type": "object", "patternProperties": { r"^\w+$": util_schema.get_action_parameters_schema() }, 'additionalProperties': False }, "output_key": { "description": "Default key to expect results to be published to.", "type": "string", "required": False }, "output_schema": { "description": "Schema for the runner's output.", "type": "object", "patternProperties": { r"^\w+$": util_schema.get_action_output_schema() }, 'additionalProperties': False, "default": {} }, }, "additionalProperties": False } 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 for key, value in kw.items(): setattr(self, key, value) if not hasattr(self, 'runner_parameters'): setattr(self, 'runner_parameters', dict()) @classmethod def to_model(cls, runner_type): name = runner_type.name description = runner_type.description enabled = getattr(runner_type, 'enabled', True) runner_package = getattr(runner_type, 'runner_package', runner_type.runner_module) runner_module = str(runner_type.runner_module) runner_parameters = getattr(runner_type, 'runner_parameters', dict()) output_key = getattr(runner_type, 'output_key', None) output_schema = getattr(runner_type, 'output_schema', dict()) query_module = getattr(runner_type, 'query_module', None) model = cls.model(name=name, description=description, enabled=enabled, runner_package=runner_package, runner_module=runner_module, runner_parameters=runner_parameters, output_schema=output_schema, query_module=query_module, output_key=output_key) return model
class ActionAPI(BaseAPI, APIUIDMixin): """ The system entity that represents a Stack Action/Automation in the system. """ model = ActionDB schema = { "title": "Action", "description": "An activity that happens as a response to the external event.", "type": "object", "properties": { "id": { "description": "The unique identifier for the action.", "type": "string" }, "ref": { "description": "System computed user friendly reference for the action. \ Provided value will be overridden by computed value.", "type": "string" }, "uid": { "type": "string" }, "name": { "description": "The name of the action.", "type": "string", "required": True }, "description": { "description": "The description of the action.", "type": "string" }, "enabled": { "description": "Enable or disable the action from invocation.", "type": "boolean", "default": True }, "runner_type": { "description": "The type of runner that executes the action.", "type": "string", "required": True }, "entry_point": { "description": "The entry point for the action.", "type": "string", "default": "" }, "pack": { "description": "The content pack this action belongs to.", "type": "string", "default": DEFAULT_PACK_NAME }, "parameters": { "description": "Input parameters for the action.", "type": "object", "patternProperties": { r"^\w+$": util_schema.get_action_parameters_schema() }, 'additionalProperties': False, "default": {} }, "output_schema": { "description": "Schema for the action's output.", "type": "object", "patternProperties": { r"^\w+$": util_schema.get_action_output_schema() }, 'additionalProperties': False, "default": {} }, "tags": { "description": "User associated metadata assigned to this object.", "type": "array", "items": { "type": "object" } }, "notify": { "description": "Notification settings for action.", "type": "object", "properties": { "on-complete": NotificationSubSchemaAPI, "on-failure": NotificationSubSchemaAPI, "on-success": NotificationSubSchemaAPI }, "additionalProperties": False }, "metadata_file": { "description": "Path to the metadata file relative to the pack directory.", "type": "string", "default": "" } }, "additionalProperties": False } def __init__(self, **kw): 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', '') @classmethod def from_model(cls, model, mask_secrets=False): action = cls._from_model(model) action['runner_type'] = action.get('runner_type', {}).get('name', None) action['tags'] = TagsHelper.from_model(model.tags) if getattr(model, 'notify', None): action['notify'] = NotificationsHelper.from_model(model.notify) return cls(**action) @classmethod def to_model(cls, action): name = getattr(action, 'name', None) description = getattr(action, 'description', None) enabled = bool(getattr(action, 'enabled', True)) entry_point = str(action.entry_point) pack = str(action.pack) runner_type = {'name': str(action.runner_type)} parameters = getattr(action, 'parameters', dict()) output_schema = getattr(action, 'output_schema', dict()) tags = TagsHelper.to_model(getattr(action, 'tags', [])) ref = ResourceReference.to_string_reference(pack=pack, name=name) if getattr(action, 'notify', None): notify = NotificationsHelper.to_model(action.notify) else: # We use embedded document model for ``notify`` in action model. If notify is # set notify to None, Mongoengine interprets ``None`` as unmodified # field therefore doesn't delete the embedded document. Therefore, we need # to use an empty document. notify = NotificationsHelper.to_model({}) metadata_file = getattr(action, 'metadata_file', None) model = cls.model(name=name, description=description, enabled=enabled, entry_point=entry_point, pack=pack, runner_type=runner_type, tags=tags, parameters=parameters, output_schema=output_schema, notify=notify, ref=ref, metadata_file=metadata_file) return model