DATAZONE Connect
DATAZONE Connect is a generic script runner for third-party system integrations. It runs as a separate Docker container and provides a REST API through which scripts can be executed with variables.
Concept
Connect follows a scripts-first approach: Every integration (DATAZONE ERP, Teams, Slack, Zammad, etc.) is a simple shell script with standardized metadata. This means maximum flexibility with minimum effort.
Architecture
DATAZONE Control DATAZONE Connect
+------------------+ +------------------+
| Playbook | Webhook Step | Flask API (5002) |
| Step 1: Script | ----------> | /api/scripts/run |
| Step 2: Task | | |
| Step 3: Webhook| ------------> | /scripts/ |
+------------------+ | erp-billing.sh |
| teams-notify.sh|
+------------------+How It Works
- Scripts are placed in the
connect/scripts/directory - Connect automatically reads metadata from script headers (
@name,@description,@var) - Variables are passed to scripts as environment variables
- Credentials (passwords, API keys) come from container environment variables, not from scripts
- Scripts return structured results via the
#RESULT:{json}convention
REST API
Health Check
GET /api/healthReturns the container status and the number of available scripts.
List Scripts
GET /api/scriptsReturns a list of all available scripts with metadata:
[
{
"name": "ERP Billing",
"filename": "erp-billing.sh",
"description": "Creates a TimeEntry in DATAZONE ERP.",
"vars": [
{"name": "CUSTOMER_NUMBER", "required": true, "description": "Customer number (e.g., 10001)"},
{"name": "CUSTOMER_NAME", "required": true, "description": "Customer name"},
{"name": "TASK", "required": true, "description": "Task description"}
]
}
]Execute Script
POST /api/scripts/run
Content-Type: application/json
{
"script": "erp-billing.sh",
"vars": {
"CUSTOMER_NUMBER": "10001",
"CUSTOMER_NAME": "Example GmbH",
"TASK": "OPNsense Firmware Update"
}
}Synchronous execution (default): Waits for the result and returns it directly.
Asynchronous execution: With ?async=true, a job is created whose status can be queried:
POST /api/scripts/run?async=true
-> {"job_id": "abc123", "status": "running"}
GET /api/jobs/abc123
-> {"status": "completed", "exit_code": 0, "result": {...}}Incoming Webhooks
POST /api/webhooks/incoming/{name}Receives external webhook calls (e.g., from Zammad, GitLab, etc.) and executes the associated script. The webhook body is passed as a WEBHOOK_BODY environment variable.
Execution Log
GET /api/logs
GET /api/logs?limit=10Returns recent script executions with status and results.
Creating Scripts
Metadata Format
Each script begins with a standardized header:
#!/bin/bash
###############################################################################
# @name My Script
# @description Brief description of what the script does.
#
# @var REQUIRED_VAR required Description of the required variable
# @var OPTIONAL_VAR optional Description of the optional variable
###############################################################################| Field | Required | Description |
|---|---|---|
@name | Yes | Display name of the script |
@description | Yes | Brief description |
@var | No | Variable with name, required/optional, and description |
Structured Return Values
Scripts can return a JSON result via the #RESULT:{json} convention:
echo "#RESULT:{\"success\":true,\"id\":42,\"message\":\"Created\"}"Connect parses the last line starting with #RESULT: and returns the JSON as the result field in the API response.
Credentials
Credentials are never stored directly in scripts. Instead, they are configured as container environment variables:
# In script: use environment variable
ERP_PASSWORD="${ERP_PASSWORD:?ERP_PASSWORD not set}"
# In docker-compose.yml: define variable
# environment:
# - ERP_PASSWORD=${ERP_PASSWORD:-}
# In .env: set value
# ERP_PASSWORD=secret123Included Scripts
ERP Billing
File: erp-billing.sh
Creates a TimeEntry in DATAZONE ERP. Replaces the legacy Nuclos/Sema integration.
| Variable | Required | Description |
|---|---|---|
CUSTOMER_NUMBER | Yes | Customer number (e.g., 10001) |
CUSTOMER_NAME | Yes | Customer name |
TASK | Yes | Task description |
DURATION_HOURS | No | Duration in hours (default: 0.5) |
HOSTNAME | No | Hostname of the affected system |
MODULE | No | Module type (opnsense, linux, etc.) |
BILLABLE | No | "true" or "false" (default: true) |
Workflow:
- JWT login at
${ERP_URL}/api/v1/auth/loginwith the service user - Resolve customer by number:
GET /api/v1/customers/resolve/{CUSTOMER_NUMBER}->customer_id(UUID) - Create TimeEntry:
POST /api/v1/tickets/time-entries/with customer_id, description, duration
If the customer is not found in ERP, the script fails with HTTP 404 (no fallback booking like the old Nuclos script).
ERP Service User
A dedicated service user must exist in ERP (without MFA!) with the following permissions:
customers:read(resolve customers)timeentries:create(create TimeEntry)timeentries:read(optional, for sync)
Environment variables (set in .env):
| Variable | Description |
|---|---|
ERP_URL | ERP server URL (e.g., https://erp.datazone.de) |
ERP_USER | Service user email |
ERP_PASSWORD | Service user password |
ERP_TENANT_SLUG | Tenant slug (default: default) |
Nuclos Billing (Legacy)
File: nuclos-billing.sh
Legacy Nuclos/Sema integration. Kept for rollback purposes only — use erp-billing.sh for new playbooks.
Teams Notification
File: teams-notify.sh
Sends a message to a Microsoft Teams webhook:
| Variable | Required | Description |
|---|---|---|
MESSAGE | Yes | Message text |
TITLE | No | Message title (default: DATAZONE Connect) |
COLOR | No | Color as hex value (default: 0076D7) |
Environment variable: TEAMS_WEBHOOK_URL must be set in .env.
Playbook Integration
Connect is integrated via the Webhook step type in playbooks. This allows integrations to be embedded directly in maintenance workflows.
Example: Maintenance with ERP Billing
| Step | Type | Action | On Error |
|---|---|---|---|
| 1 | VM Snapshot | Create snapshot | stop |
| 2 | Task | PVE_UPDATE | continue |
| 3 | Check Online | Wait until online | stop |
| 4 | Webhook | ERP Billing (book 30 min) | continue |
| 5 | Webhook | Teams notification | continue |
Example: Webhook Step Configuration
For the webhook step in the playbook:
| Field | Value |
|---|---|
| URL | http://datazone-connect:5002/api/scripts/run |
| Method | POST |
| Body | {"script":"erp-billing.sh","vars":{"CUSTOMER_NUMBER":"{customer_number}","CUSTOMER_NAME":"{customer_name}","TASK":"Maintenance {hostname}","DURATION_HOURS":"0.5","HOSTNAME":"{hostname}","MODULE":"{module}"}} |
| Headers | Content-Type: application/json |
The placeholders {customer_number}, {customer_name}, {hostname}, and {module} are automatically replaced with data from the current host.
Docker Configuration
Connect runs as a separate container in the Docker network:
connect:
build: ./connect
container_name: datazone-connect
environment:
- CONNECT_TOKEN=${CONNECT_TOKEN:-}
# DATAZONE ERP integration
- ERP_URL=${ERP_URL:-}
- ERP_USER=${ERP_USER:-}
- ERP_PASSWORD=${ERP_PASSWORD:-}
- ERP_TENANT_SLUG=${ERP_TENANT_SLUG:-default}
# Webhook URLs
- TEAMS_WEBHOOK_URL=${TEAMS_WEBHOOK_URL:-}
volumes:
- ./connect/scripts:/scripts:ro
networks:
- datazone-net
restart: unless-stoppedCustom Scripts
Simply place custom scripts in the connect/scripts/ directory. The container mounts this directory as a read-only volume. After adding new scripts, no restart is needed — they are automatically detected on the next API call.
Security
Connect is only accessible within the Docker network and not reachable from outside. For additional security, a CONNECT_TOKEN can be configured.