598 lines
14 KiB
Markdown
598 lines
14 KiB
Markdown
# Action Management API
|
|
|
|
This document describes the Action Management API endpoints for the Attune automation platform.
|
|
|
|
## Overview
|
|
|
|
Actions are the executable units in Attune that perform specific tasks. Each action belongs to a pack and can have parameters, output schemas, and runtime requirements.
|
|
|
|
**Base Path:** `/api/v1/actions`
|
|
|
|
## Data Model
|
|
|
|
### Action
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack": 1,
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request to a specified URL",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"param_schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"url": { "type": "string" },
|
|
"headers": { "type": "object" }
|
|
},
|
|
"required": ["url"]
|
|
},
|
|
"out_schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"status_code": { "type": "integer" },
|
|
"body": { "type": "string" }
|
|
}
|
|
},
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T10:00:00Z"
|
|
}
|
|
```
|
|
|
|
### Action Summary (List View)
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request to a specified URL",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T10:00:00Z"
|
|
}
|
|
```
|
|
|
|
## Endpoints
|
|
|
|
### List All Actions
|
|
|
|
Retrieve a paginated list of all actions.
|
|
|
|
**Endpoint:** `GET /api/v1/actions`
|
|
|
|
**Query Parameters:**
|
|
- `page` (integer, optional): Page number (default: 1)
|
|
- `per_page` (integer, optional): Items per page (default: 20, max: 100)
|
|
|
|
**Response:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T10:00:00Z"
|
|
}
|
|
],
|
|
"pagination": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 1,
|
|
"total_pages": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### List Actions by Pack
|
|
|
|
Retrieve all actions belonging to a specific pack.
|
|
|
|
**Endpoint:** `GET /api/v1/packs/:pack_ref/actions`
|
|
|
|
**Path Parameters:**
|
|
- `pack_ref` (string): Pack reference identifier
|
|
|
|
**Query Parameters:**
|
|
- `page` (integer, optional): Page number (default: 1)
|
|
- `per_page` (integer, optional): Items per page (default: 20, max: 100)
|
|
|
|
**Response:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T10:00:00Z"
|
|
}
|
|
],
|
|
"pagination": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 1,
|
|
"total_pages": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404 Not Found`: Pack with the specified ref does not exist
|
|
|
|
---
|
|
|
|
### Get Action by Reference
|
|
|
|
Retrieve a single action by its reference identifier.
|
|
|
|
**Endpoint:** `GET /api/v1/actions/:ref`
|
|
|
|
**Path Parameters:**
|
|
- `ref` (string): Action reference identifier (e.g., "core.http.get")
|
|
|
|
**Response:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack": 1,
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request to a specified URL",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"param_schema": { ... },
|
|
"out_schema": { ... },
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T10:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404 Not Found`: Action with the specified ref does not exist
|
|
|
|
---
|
|
|
|
### Create Action
|
|
|
|
Create a new action in the system.
|
|
|
|
**Endpoint:** `POST /api/v1/actions`
|
|
|
|
**Request Body:**
|
|
|
|
```json
|
|
{
|
|
"ref": "core.http.get",
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request to a specified URL",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"param_schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"url": { "type": "string" },
|
|
"headers": { "type": "object" }
|
|
},
|
|
"required": ["url"]
|
|
},
|
|
"out_schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"status_code": { "type": "integer" },
|
|
"body": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Required Fields:**
|
|
- `ref`: Unique reference identifier (alphanumeric, dots, underscores, hyphens)
|
|
- `pack_ref`: Reference to the parent pack
|
|
- `label`: Human-readable name (1-255 characters)
|
|
- `description`: Action description (min 1 character)
|
|
- `entrypoint`: Execution entry point (1-1024 characters)
|
|
|
|
**Optional Fields:**
|
|
- `runtime`: Runtime ID for execution environment
|
|
- `param_schema`: JSON Schema defining input parameters
|
|
- `out_schema`: JSON Schema defining expected outputs
|
|
|
|
**Response:** `201 Created`
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack": 1,
|
|
"pack_ref": "core",
|
|
"label": "HTTP GET Request",
|
|
"description": "Performs an HTTP GET request to a specified URL",
|
|
"entrypoint": "/actions/http_get.py",
|
|
"runtime": 1,
|
|
"param_schema": { ... },
|
|
"out_schema": { ... },
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T10:00:00Z"
|
|
},
|
|
"message": "Action created successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400 Bad Request`: Invalid request data or validation failure
|
|
- `404 Not Found`: Referenced pack does not exist
|
|
- `409 Conflict`: Action with the same ref already exists
|
|
|
|
---
|
|
|
|
### Update Action
|
|
|
|
Update an existing action's properties.
|
|
|
|
**Endpoint:** `PUT /api/v1/actions/:ref`
|
|
|
|
**Path Parameters:**
|
|
- `ref` (string): Action reference identifier
|
|
|
|
**Request Body:**
|
|
|
|
All fields are optional. Only provided fields will be updated.
|
|
|
|
```json
|
|
{
|
|
"label": "Updated HTTP GET Request",
|
|
"description": "Updated description",
|
|
"entrypoint": "/actions/http_get_v2.py",
|
|
"runtime": 2,
|
|
"param_schema": { ... },
|
|
"out_schema": { ... }
|
|
}
|
|
```
|
|
|
|
**Response:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": 1,
|
|
"ref": "core.http.get",
|
|
"pack": 1,
|
|
"pack_ref": "core",
|
|
"label": "Updated HTTP GET Request",
|
|
"description": "Updated description",
|
|
"entrypoint": "/actions/http_get_v2.py",
|
|
"runtime": 2,
|
|
"param_schema": { ... },
|
|
"out_schema": { ... },
|
|
"created": "2024-01-13T10:00:00Z",
|
|
"updated": "2024-01-13T12:00:00Z"
|
|
},
|
|
"message": "Action updated successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400 Bad Request`: Invalid request data or validation failure
|
|
- `404 Not Found`: Action with the specified ref does not exist
|
|
|
|
---
|
|
|
|
### Delete Action
|
|
|
|
Delete an action from the system.
|
|
|
|
**Endpoint:** `DELETE /api/v1/actions/:ref`
|
|
|
|
**Path Parameters:**
|
|
- `ref` (string): Action reference identifier
|
|
|
|
**Response:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Action 'core.http.get' deleted successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404 Not Found`: Action with the specified ref does not exist
|
|
|
|
---
|
|
|
|
### Get Queue Statistics
|
|
|
|
Retrieve real-time queue statistics for an action's execution queue.
|
|
|
|
**Endpoint:** `GET /api/v1/actions/:ref/queue-stats`
|
|
|
|
**Path Parameters:**
|
|
- `ref` (string): Action reference identifier
|
|
|
|
**Response:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"action_id": 1,
|
|
"action_ref": "core.http.get",
|
|
"queue_length": 5,
|
|
"active_count": 2,
|
|
"max_concurrent": 3,
|
|
"oldest_enqueued_at": "2025-01-27T10:30:00Z",
|
|
"total_enqueued": 1250,
|
|
"total_completed": 1245,
|
|
"last_updated": "2025-01-27T12:45:30Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response Fields:**
|
|
- `action_id`: Numeric action ID
|
|
- `action_ref`: Action reference identifier
|
|
- `queue_length`: Number of executions waiting in queue
|
|
- `active_count`: Number of currently running executions
|
|
- `max_concurrent`: Maximum concurrent executions allowed (from policy)
|
|
- `oldest_enqueued_at`: Timestamp of oldest queued execution (null if queue empty)
|
|
- `total_enqueued`: Lifetime count of executions enqueued
|
|
- `total_completed`: Lifetime count of executions completed
|
|
- `last_updated`: Last time statistics were updated
|
|
|
|
**Response When No Queue Stats Available:** `200 OK`
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"action_id": 1,
|
|
"action_ref": "core.http.get",
|
|
"queue_length": 0,
|
|
"active_count": 0,
|
|
"max_concurrent": null,
|
|
"oldest_enqueued_at": null,
|
|
"total_enqueued": 0,
|
|
"total_completed": 0,
|
|
"last_updated": null
|
|
}
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404 Not Found`: Action with the specified ref does not exist
|
|
|
|
**Use Cases:**
|
|
- Monitor action execution queue depth
|
|
- Detect stuck or growing queues
|
|
- Track execution throughput
|
|
- Validate policy enforcement
|
|
- Operational dashboards
|
|
|
|
**Related Documentation:**
|
|
- [Queue Architecture](./queue-architecture.md)
|
|
- [Policy Enforcement](./executor-service.md#policy-enforcement)
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### Creating a Simple Action
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/v1/actions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"ref": "mypack.hello_world",
|
|
"pack_ref": "mypack",
|
|
"label": "Hello World",
|
|
"description": "Prints hello world",
|
|
"entrypoint": "/actions/hello.py"
|
|
}'
|
|
```
|
|
|
|
### Creating an Action with Parameter Schema
|
|
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/v1/actions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"ref": "mypack.send_email",
|
|
"pack_ref": "mypack",
|
|
"label": "Send Email",
|
|
"description": "Sends an email message",
|
|
"entrypoint": "/actions/send_email.py",
|
|
"param_schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"to": { "type": "string", "format": "email" },
|
|
"subject": { "type": "string" },
|
|
"body": { "type": "string" }
|
|
},
|
|
"required": ["to", "subject", "body"]
|
|
}
|
|
}'
|
|
```
|
|
|
|
### Listing Actions for a Pack
|
|
|
|
```bash
|
|
curl http://localhost:3000/api/v1/packs/core/actions
|
|
```
|
|
|
|
### Updating an Action
|
|
|
|
```bash
|
|
curl -X PUT http://localhost:3000/api/v1/actions/mypack.hello_world \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"label": "Hello World v2",
|
|
"description": "Updated hello world action"
|
|
}'
|
|
```
|
|
|
|
### Deleting an Action
|
|
|
|
```bash
|
|
curl -X DELETE http://localhost:3000/api/v1/actions/mypack.hello_world
|
|
```
|
|
|
|
### Getting Queue Statistics
|
|
|
|
```bash
|
|
curl http://localhost:3000/api/v1/actions/core.http.get/queue-stats
|
|
```
|
|
|
|
**Example Response:**
|
|
```json
|
|
{
|
|
"data": {
|
|
"action_id": 1,
|
|
"action_ref": "core.http.get",
|
|
"queue_length": 12,
|
|
"active_count": 5,
|
|
"max_concurrent": 5,
|
|
"oldest_enqueued_at": "2025-01-27T12:40:00Z",
|
|
"total_enqueued": 523,
|
|
"total_completed": 511,
|
|
"last_updated": "2025-01-27T12:45:30Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Validation Rules
|
|
|
|
### Action Reference (`ref`)
|
|
- Must be unique across all actions
|
|
- Can contain alphanumeric characters, dots (.), underscores (_), and hyphens (-)
|
|
- Typically follows the pattern: `pack_name.action_name`
|
|
- Example: `core.http.get`, `aws.ec2.start_instance`
|
|
|
|
### Pack Reference (`pack_ref`)
|
|
- Must reference an existing pack
|
|
- The pack must exist before creating actions for it
|
|
|
|
### Entry Point (`entrypoint`)
|
|
- Path or identifier for the executable code
|
|
- Can be a file path, module name, function name, etc.
|
|
- Format depends on the runtime environment
|
|
|
|
### Schemas (`param_schema`, `out_schema`)
|
|
- Must be valid JSON Schema documents
|
|
- Used for validation during action execution
|
|
- Helps with auto-generating documentation and UI
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Naming Conventions**
|
|
- Use descriptive, hierarchical names: `pack.category.action`
|
|
- Keep names concise but meaningful
|
|
- Use lowercase with dots as separators
|
|
|
|
2. **Schema Definitions**
|
|
- Always provide `param_schema` for clarity
|
|
- Define `required` fields in schemas
|
|
- Use appropriate JSON Schema types and formats
|
|
- Document schema fields with descriptions
|
|
|
|
3. **Entry Points**
|
|
- Use consistent paths relative to the pack root
|
|
- Keep entry points simple and maintainable
|
|
- Consider versioning: `/actions/v1/http_get.py`
|
|
|
|
4. **Runtime Association**
|
|
- Specify runtime when actions have specific dependencies
|
|
- Null runtime means use default/generic runtime
|
|
- Ensure runtime exists before creating action
|
|
|
|
5. **Error Handling**
|
|
- Design actions to handle errors gracefully
|
|
- Use output schemas to define error structures
|
|
- Log execution details for debugging
|
|
|
|
6. **Queue Monitoring**
|
|
- Use `/queue-stats` endpoint to monitor execution queues
|
|
- Alert on high `queue_length` (> 100)
|
|
- Investigate when `oldest_enqueued_at` is old (> 30 minutes)
|
|
- Track completion rate: `total_completed / total_enqueued`
|
|
|
|
---
|
|
|
|
## Queue Statistics
|
|
|
|
The `/queue-stats` endpoint provides real-time visibility into action execution queues.
|
|
|
|
### Understanding Queue Metrics
|
|
|
|
- **queue_length**: Executions waiting to run (0 = healthy)
|
|
- **active_count**: Executions currently running
|
|
- **max_concurrent**: Policy-enforced concurrency limit
|
|
- **oldest_enqueued_at**: How long the oldest execution has been waiting
|
|
- **total_enqueued/completed**: Lifetime throughput metrics
|
|
|
|
### Healthy vs Unhealthy Queues
|
|
|
|
**Healthy:**
|
|
- ✅ `queue_length` is 0 or low (< 10)
|
|
- ✅ `active_count` ≈ `max_concurrent` during load
|
|
- ✅ `oldest_enqueued_at` is recent (< 5 minutes)
|
|
- ✅ `total_completed` increases steadily
|
|
|
|
**Unhealthy:**
|
|
- ⚠️ `queue_length` consistently high (> 50)
|
|
- ⚠️ `oldest_enqueued_at` is old (> 30 minutes)
|
|
- 🚨 Queue not progressing (stats not updating)
|
|
- 🚨 `active_count` < `max_concurrent` (workers stuck)
|
|
|
|
### Monitoring Recommendations
|
|
|
|
1. **Set up alerts** for high queue depths
|
|
2. **Track trends** in `total_enqueued` vs `total_completed`
|
|
3. **Investigate spikes** in `queue_length`
|
|
4. **Scale workers** when queues consistently fill
|
|
5. **Adjust policies** if concurrency limits are too restrictive
|
|
|
|
For detailed queue architecture and troubleshooting, see [Queue Architecture Documentation](./queue-architecture.md).
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [Pack Management API](./api-packs.md)
|
|
- [Runtime Management API](./api-runtimes.md)
|
|
- [Rule Management API](./api-rules.md)
|
|
- [Execution API](./api-executions.md)
|
|
- [Queue Architecture](./queue-architecture.md)
|
|
- [Executor Service](./executor-service.md)
|
|
|
|
---
|
|
|
|
**Last Updated:** January 27, 2025 |