Skip to content

Commit

Permalink
feat: major refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
joostfaassen committed May 3, 2020
1 parent 5e247f2 commit e53e1dd
Show file tree
Hide file tree
Showing 48 changed files with 2,708 additions and 920 deletions.
172 changes: 157 additions & 15 deletions README.md
Expand Up @@ -5,30 +5,172 @@ Inspired by the trends in Serverless / FaaS / Cloud Functions.

## Features:

* Provides a framework to build, call and test reusable, stateless, language agnostic functions (actions).
* A language agnostic (json) format to define `inputs`, `outputs` and `configs` that your actions need.
* "Exo Actions" are bundled into reusable "Exo Packages"
* Configure your Exo instance with a `exo.config.json` file, importing all the packages your app needs.
* Uses JSON Schema to validate every request, response, input, output and config.
* An HTTP end-point server to serve your functions.
* A Console tool to help build, test and debug your Exo functions.
* Provides a framework to build, call and test reusable, stateless, language agnostic functions (Exo Actions).
* A language agnostic YAML format to define the metadata of your Exo Actions, specifying their name, description, tags and detailed `input` and `output` schemas.
* Uses JSON Schema to validate every request, response, input and output.
* An HTTP end-point server to serve your Exo Actions (exo-server).
* A Console tool to help build, test and debug your Exo Actions.

## Examples:
## Project status

The `example/` directory contains an example package with 2 functions, one implemented in PHP, and one generically executing an external CLI tool.
Exo is currently in an experimental phase, and some of the features are under construction.

## core-exo-actions:

Check out https://github.com/linkorb/core-exo-actions for a range of library of reusable common Exo actions.

To test it out:

cp .env.dist .env
edit .env # setup your EXO_CONFIG path
bin/exo action example/hello-php -i greeting=Hello -i name=Alice
bin/exo run example/hello-php -i greeting=Hello -i name=Alice
edit .env # setup your EXO_ACTIONS path

This will call the `hello-php` Action, passing input arguments through stdin.
# List all available actions
bin/exo action

## Status
# Inspect a particular action (hello-php)
bin/exo action hello-php -i greeting=Hello -i name=Alice

Exo is currently in an experimental phase, and some of the features are under construction.
# Run a particular action (hello-php) with specified input values
bin/exo run hello-php -i greeting=Hello -i name=Alice

# Handle a full JSON request
bin/exo request < request.json

## Custom actions

It's easy to implement your own actions, in your language of choice, usually in just a few lines of code.

Check out the core-exo-actions repository for a set of "hello world" examples in PHP, node.js and Bash (most other common languages supported too).

To use your actions in Exo (CLI, Worker, Server), simply add the path to your actions to the EXO_ACTIONS environment variable.

## Request/Response JSON

Exo transforms JSON requests into JSON responses.

### Requests

A request contains:

1. the action name: determines which action to run
2. an optional set of input variables (may be strings, integers, objects): passed as input to the action
3. an optional list of output mappings: applied on output variables

```json
{
"action": "random-number",
"input": {
"min": "100",
"max": "200"
},
"mapping": {
"result": "surprise"
}
}
```

You can execute this request (and pretty-print + color-code it using `jq`) like this:

bin/exo request < request.json | jq

Response:

```json
{
"status": "OK",
"output": {
"surprise": "123"
}
}
``


### Handling a request

When Exo receives the request, it will

0. Find the action information (input/output variables)
0. Validate the full request against data/request.schema.json
0. Validate the input variables against the input JSON schema of the requested action
0. Execute the action
0. Validate the output variables againt the output JSON schema of the requested action
0. Optionally apply output variable mapping (renaming)
0. Validate the full response against data/response.schema.json
0. Return the response JSON

### Response

Example response:

```json
{
"status": "OK",
"output": {
"sentence": "Hello, Joe"
}
}
```

A response contains a `status` that contains either `OK` or `ERROR`.

If the action has any output variables, they are specified in the `output` object (optional mappings applied)

## Variables (URLs, Credentials, etc)

You can variables and secrets to your exo instance as environment variables. Make sure the environment variables are prefixed with `EXO__VARIABLE__`. For example:

EXO__VARIABLE__MATTERMOST_URL=https://mattermost.example.com/hooks/xyz123abc

You can now use these variables in your input variables:

./bin/exo run mattermost-send-message -i url={{MATTERMOST_URL}} -i channel=@alice -i text=Hi

The variables are only accessible by the Exo instance, but any request can refer to them. This makes it easy to call actions from client applications (i.e. Camunda) without passing around hardcoded URLs and credentials in your client code, processes, etc.

## Workers

You can run Exo as a worker. In this mode, Exo waits for requests, executes them, and returns the responses.

To know where to find requests, you can specify the type of worker, and any options that worker needs to be instantiated.

Currently the Camunda worker is available. In the future a Kafka, Rabbitmq, or any other type of worker can be implemented easily.

To run the worker, simply run:

bin/exo worker

### Camunda Worker

The Camunda worker requires the following environment variables:

* `EXO__WORKER__TYPE`: Worker implementation, i.e. `Camunda`
* `EXO__WORKER__URL`: Base URL for the Camunda REST API, i.e. `http://127.0.0.1:8888/engine-rest`
* `EXO__WORKER__USERNAME`: Username to authenticate with, i.e. `exo`
* `EXO__WORKER__PASSWORD`: Password to authenticate with

It is recommended to create a dedicated user for Exo. This way each task is performed by the appropriate user, ensuring that Camunda permissions and logging are correctly related to Exo.

Once the worker is running, you can now create "Service Tasks" in your processes that trigger Exo actions.

In the Camunda modeler, create a "Task" and use the wrench to turn it into a "Service Task".

In the Properties Panel, set the Implementation as "External", and enter a topic. The Topic should always be prefixed with `exo:` followed by the action name you'd like to execute. For example: `exo:smtp-send`.

Open the Input/Output tab to specify input variables to your action. You can use any process variables and exo variables.

Example inputs:

* `to`: `joe@example.web`
* `from`: `Exo bot`
* `subject`: `Hello world!`
* `body`: `This is a demo`
* `dsn`: `smtp://user:pass@mail.example.web`

You can also specify an environment variable called `EXO__VARIABLES__SMTP_DSN` and specify `{{SMTP_DSN}}` as the `dsn` value. This way you don't need to hard-code the SMTP details in your BPMN process.

You can also specify `${someProcessVariable}` as a value to inject a process variable.

For actions that have output variables, you may wish to rename those before injecting them back into your process. For example, if a `get-user-data` action returns a `user` object, you may wish to rename this to `customer` (in order not to overwrite or handle multiple `user` variables in your process). This can be achieved by specifying an input variable `>user` with value `customer`.

## License

Expand Down
5 changes: 3 additions & 2 deletions bin/exo
Expand Up @@ -28,8 +28,9 @@ if (file_exists($filename)) {


$application = new Application('Exo CLI', '1.0.0');
$application->setCatchExceptions(true);
$application->add(new \Exo\Console\Command\ConfigCommand());
$application->setCatchExceptions(false);
$application->add(new \Exo\Console\Command\ActionCommand());
$application->add(new \Exo\Console\Command\RunCommand());
$application->add(new \Exo\Console\Command\RequestCommand());
$application->add(new \Exo\Console\Command\WorkerCommand());
$application->run();
10 changes: 9 additions & 1 deletion composer.json
Expand Up @@ -17,7 +17,15 @@
"symfony/yaml": "^3.0|^4.0",
"linkorb/boost": "^1.0",
"linkorb/collection": "^1.0",
"symfony/process": "^3.0|^4.0"
"symfony/process": "^3.0|^4.0",
"symfony/http-client": "^4.3",
"psr/http-client": "^1.0",
"nyholm/psr7": "^1.1",
"symfony/mailer": "^5.0",
"symfony/mime": "^5.0",
"gnello/php-mattermost-driver": "^2.12",
"thibaud-dauce/mattermost-php": "^1.2",
"linkorb/config": "^1.0"
},
"require-dev": {
"symfony/dotenv": "^3.0|^4.0",
Expand Down

0 comments on commit e53e1dd

Please sign in to comment.