Replace Go API with PocketBase; update docs

Remove the old Go/Mongo API (api/main.go, go.mod, go.sum, .env.example) and switch telemetry backend to PocketBase (http://db.community-scripts.org). Update documentation and flowcharts to reflect the PocketBase collection (_dev_telemetry_data), new REST endpoints (POST/PATCH/GET), field schema, and revised api.func integration (LXC/VM reporting and status updates). Misc scripts and helpers were adjusted (misc/api.func, misc/build.func, misc/error_handler.func) and a new misc/ingest.go was added. This consolidates telemetry to a hosted PocketBase instance and updates docs and integration points accordingly.
This commit is contained in:
CanbiZ (MickLesk)
2026-02-09 15:34:17 +01:00
parent 1eb0cc55ff
commit 820d4551a1
14 changed files with 1137 additions and 2557 deletions

View File

@@ -2,63 +2,88 @@
## Overview
This document provides a comprehensive alphabetical reference of all functions in `api.func`, including parameters, dependencies, usage examples, and error handling.
This document provides a comprehensive reference of all functions in `api.func`, including parameters, dependencies, usage examples, and error handling. The backend is **PocketBase** hosted at `http://db.community-scripts.org`.
## Configuration Variables
| Variable | Value | Description |
|----------|-------|-------------|
| `PB_URL` | `http://db.community-scripts.org` | PocketBase server URL |
| `PB_COLLECTION` | `_dev_telemetry_data` | PocketBase collection name |
| `PB_API_URL` | `${PB_URL}/api/collections/${PB_COLLECTION}/records` | Full API endpoint |
| `PB_RECORD_ID` | *(runtime)* | Stores the PocketBase record ID returned by POST for later PATCH calls |
## Function Categories
### Error Description Functions
#### `get_error_description()`
#### `explain_exit_code()`
**Purpose**: Convert numeric exit codes to human-readable explanations
**Parameters**:
- `$1` - Exit code to explain
- `$1` Exit code to explain
**Returns**: Human-readable error explanation string
**Side Effects**: None
**Dependencies**: None
**Environment Variables Used**: None
**Supported Exit Codes**:
- **General System**: 0-9, 18, 22, 28, 35, 56, 60, 125-128, 129-143, 152, 255
- **LXC-Specific**: 100-101, 200-209
- **Docker**: 125
> **Note**: `explain_exit_code()` is the **canonical** function for exit-code mapping. It is used by both `api.func` (telemetry) and `error_handler.func` (error display).
**Supported Exit Code Ranges** (non-overlapping):
| Range | Category |
|-------|----------|
| 12 | Generic / Shell |
| 635 | curl / wget |
| 100102 | APT / Package manager |
| 124143 | System / Signals |
| 150154 | Systemd / Service |
| 160162 | Python / pip / uv |
| 170173 | PostgreSQL |
| 180183 | MySQL / MariaDB |
| 190193 | MongoDB |
| 200231 | Proxmox custom codes |
| 243249 | Node.js / npm |
| 255 | DPKG fatal |
**Usage Example**:
```bash
error_msg=$(get_error_description 127)
error_msg=$(explain_exit_code 127)
echo "Error 127: $error_msg"
# Output: Error 127: Command not found: Incorrect path or missing dependency.
# Output: Error 127: Command not found
```
**Error Code Examples**:
```bash
get_error_description 0 # " " (space)
get_error_description 1 # "General error: An unspecified error occurred."
get_error_description 127 # "Command not found: Incorrect path or missing dependency."
get_error_description 200 # "LXC creation failed."
get_error_description 255 # "Unknown critical error, often due to missing permissions or broken scripts."
explain_exit_code 1 # "General error / Operation not permitted"
explain_exit_code 22 # "curl: HTTP error returned (404, 429, 500+)"
explain_exit_code 127 # "Command not found"
explain_exit_code 200 # "Proxmox: Failed to create lock file"
explain_exit_code 255 # "DPKG: Fatal internal error"
explain_exit_code 999 # "Unknown error"
```
### API Communication Functions
#### `post_to_api()`
**Purpose**: Send LXC container installation data to community-scripts.org API
**Purpose**: Create an LXC container telemetry record in PocketBase
**Parameters**: None (uses environment variables)
**Returns**: None
**Side Effects**:
- Sends HTTP POST request to API
- Stores response in RESPONSE variable
- Requires curl command and network connectivity
- Sends HTTP **POST** to `PB_API_URL`
- Stores the returned PocketBase record `id` in `PB_RECORD_ID` for later PATCH updates
**Dependencies**: `curl` command
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `CT_TYPE`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `DISABLEIP6`, `NSAPP`, `METHOD`
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `CT_TYPE`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `NSAPP`, `METHOD`
**Prerequisites**:
- `curl` command must be available
- `DIAGNOSTICS` must be set to "yes"
- `curl` must be available
- `DIAGNOSTICS` must be `"yes"`
- `RANDOM_UUID` must be set and not empty
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
**API Endpoint**: `POST http://db.community-scripts.org/api/collections/_dev_telemetry_data/records`
**JSON Payload Structure**:
**JSON Payload**:
```json
{
"ct_type": 1,
@@ -68,7 +93,6 @@ get_error_description 255 # "Unknown critical error, often due to missing perm
"ram_size": 2048,
"os_type": "debian",
"os_version": "12",
"disableip6": "true",
"nsapp": "plex",
"method": "install",
"pve_version": "8.0",
@@ -77,6 +101,10 @@ get_error_description 255 # "Unknown critical error, often due to missing perm
}
```
**Response Handling**:
- On HTTP 200/201, `PB_RECORD_ID` is extracted from the response JSON (`"id"` field)
- On failure, the function returns silently without blocking the installation
**Usage Example**:
```bash
export DIAGNOSTICS="yes"
@@ -91,39 +119,39 @@ export NSAPP="plex"
export METHOD="install"
post_to_api
# PB_RECORD_ID is now set (e.g. "abc123def456789")
```
#### `post_to_api_vm()`
**Purpose**: Send VM installation data to community-scripts.org API
**Purpose**: Create a VM telemetry record in PocketBase
**Parameters**: None (uses environment variables)
**Returns**: None
**Side Effects**:
- Sends HTTP POST request to API
- Stores response in RESPONSE variable
- Requires curl command and network connectivity
- Sends HTTP **POST** to `PB_API_URL`
- Stores the returned PocketBase record `id` in `PB_RECORD_ID`
**Dependencies**: `curl` command, diagnostics file
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `NSAPP`, `METHOD`
**Environment Variables Used**: `RANDOM_UUID`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `NSAPP`, `METHOD`
**Prerequisites**:
- `/usr/local/community-scripts/diagnostics` file must exist
- `DIAGNOSTICS` must be set to "yes" in diagnostics file
- `curl` command must be available
- `DIAGNOSTICS` must be `"yes"` in that file (read at runtime)
- `curl` must be available
- `RANDOM_UUID` must be set and not empty
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
**API Endpoint**: `POST http://db.community-scripts.org/api/collections/_dev_telemetry_data/records`
**JSON Payload Structure**:
**JSON Payload**:
```json
{
"ct_type": 2,
"type": "vm",
"disk_size": 8,
"core_count": 2,
"ram_size": 2048,
"os_type": "debian",
"os_version": "12",
"disableip6": "",
"nsapp": "plex",
"disk_size": 20,
"core_count": 4,
"ram_size": 4096,
"os_type": "ubuntu",
"os_version": "22.04",
"nsapp": "nextcloud",
"method": "install",
"pve_version": "8.0",
"status": "installing",
@@ -131,50 +159,81 @@ post_to_api
}
```
> **Note**: `DISK_SIZE` is stripped of its `G` suffix before sending (e.g. `"20G"` → `20`).
**Usage Example**:
```bash
# Create diagnostics file
mkdir -p /usr/local/community-scripts
echo "DIAGNOSTICS=yes" > /usr/local/community-scripts/diagnostics
export RANDOM_UUID="$(uuidgen)"
export DISK_SIZE="8G"
export CORE_COUNT=2
export RAM_SIZE=2048
export var_os="debian"
export var_version="12"
export NSAPP="plex"
export DISK_SIZE="20G"
export CORE_COUNT=4
export RAM_SIZE=4096
export var_os="ubuntu"
export var_version="22.04"
export NSAPP="nextcloud"
export METHOD="install"
post_to_api_vm
# PB_RECORD_ID is now set
```
#### `post_update_to_api()`
**Purpose**: Send installation completion status to community-scripts.org API
**Purpose**: Update an existing PocketBase record with installation completion status via PATCH
**Parameters**:
- `$1` - Status ("success" or "failed", default: "failed")
- `$2` - Exit code (default: 1)
- `$1` Status (`"done"`, `"success"`, or `"failed"`; default: `"failed"`)
- `$2` Exit code (numeric, default: `1`)
**Returns**: None
**Side Effects**:
- Sends HTTP POST request to API
- Sets POST_UPDATE_DONE=true to prevent duplicates
- Stores response in RESPONSE variable
**Dependencies**: `curl` command, `get_error_description()`
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`
- Sends HTTP **PATCH** to `PB_API_URL/{record_id}`
- Sets `POST_UPDATE_DONE=true` to prevent duplicate calls
**Dependencies**: `curl`, `explain_exit_code()`
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `PB_RECORD_ID`
**Prerequisites**:
- `curl` command must be available
- `DIAGNOSTICS` must be set to "yes"
- `curl` must be available
- `DIAGNOSTICS` must be `"yes"`
- `RANDOM_UUID` must be set and not empty
- POST_UPDATE_DONE must be false (prevents duplicates)
- `POST_UPDATE_DONE` must not be `"true"` (prevents duplicate updates)
**API Endpoint**: `http://api.community-scripts.org/dev/upload/updatestatus`
**Record Lookup**:
1. If `PB_RECORD_ID` is already set (from a prior `post_to_api` / `post_to_api_vm` call), it is used directly.
2. Otherwise, the function performs a **GET** lookup:
```
GET PB_API_URL?filter=(random_id='<RANDOM_UUID>')&fields=id&perPage=1
```
3. If no record is found, the function sets `POST_UPDATE_DONE=true` and returns.
**JSON Payload Structure**:
**Status Mapping** (PocketBase select field values: `installing`, `sucess`, `failed`, `unknown`):
| Input Status | PocketBase `status` | `exit_code` | `error` |
|---|---|---|---|
| `"done"` / `"success"` / `"sucess"` | `"sucess"` | `0` | `""` |
| `"failed"` | `"failed"` | *from $2* | *from `explain_exit_code()`* |
| anything else | `"unknown"` | *from $2* | *from `explain_exit_code()`* |
> **Note**: The PocketBase schema intentionally spells success as `"sucess"`.
**API Endpoint**: `PATCH http://db.community-scripts.org/api/collections/_dev_telemetry_data/records/{record_id}`
**JSON Payload**:
```json
{
"status": "success",
"error": "Error description from get_error_description()",
"random_id": "uuid-string"
"status": "sucess",
"error": "",
"exit_code": 0
}
```
or for failures:
```json
{
"status": "failed",
"error": "Command not found",
"exit_code": 127
}
```
@@ -183,10 +242,10 @@ post_to_api_vm
export DIAGNOSTICS="yes"
export RANDOM_UUID="$(uuidgen)"
# Report successful installation
post_update_to_api "success" 0
# After a successful installation
post_update_to_api "done" 0
# Report failed installation
# After a failed installation
post_update_to_api "failed" 127
```
@@ -196,198 +255,250 @@ post_update_to_api "failed" 127
```
post_to_api()
├── Check curl availability
├── Check DIAGNOSTICS setting
├── Check RANDOM_UUID
├── Check DIAGNOSTICS == "yes"
├── Check RANDOM_UUID is set
├── Get PVE version
├── Create JSON payload
── Send HTTP POST request
├── Create JSON payload (ct_type=1, type="lxc", status="installing")
── POST to PB_API_URL
└── Extract PB_RECORD_ID from response
post_to_api_vm()
├── Check diagnostics file
├── Read DIAGNOSTICS from /usr/local/community-scripts/diagnostics
├── Check curl availability
├── Check DIAGNOSTICS setting
├── Check RANDOM_UUID
├── Process disk size
├── Check DIAGNOSTICS == "yes"
├── Check RANDOM_UUID is set
├── Strip 'G' suffix from DISK_SIZE
├── Get PVE version
├── Create JSON payload
── Send HTTP POST request
├── Create JSON payload (ct_type=2, type="vm", status="installing")
── POST to PB_API_URL
└── Extract PB_RECORD_ID from response
post_update_to_api()
├── Check POST_UPDATE_DONE flag
post_update_to_api(status, exit_code)
├── Check curl availability
├── Check DIAGNOSTICS setting
├── Check RANDOM_UUID
├── Determine status and exit code
├── Get error description
├── Create JSON payload
├── Send HTTP POST request
├── Check POST_UPDATE_DONE flag
├── Check DIAGNOSTICS == "yes"
├── Check RANDOM_UUID is set
├── Map status → pb_status ("done"→"sucess", "failed"→"failed", *→"unknown")
├── For failed/unknown: call explain_exit_code(exit_code)
├── Resolve record_id (PB_RECORD_ID or GET lookup by random_id)
├── PATCH to PB_API_URL/{record_id}
└── Set POST_UPDATE_DONE=true
```
### Error Description Flow
```
get_error_description()
├── Match exit code
├── Return appropriate description
└── Handle unknown codes
explain_exit_code(code)
├── Match code against case statement (non-overlapping ranges)
├── Return description string
└── Default: "Unknown error"
```
## Error Code Reference
### General System Errors
### Generic / Shell (12)
| Code | Description |
|------|-------------|
| 0 | (space) |
| 1 | General error: An unspecified error occurred. |
| 2 | Incorrect shell usage or invalid command arguments. |
| 3 | Unexecuted function or invalid shell condition. |
| 4 | Error opening a file or invalid path. |
| 5 | I/O error: An input/output failure occurred. |
| 6 | No such device or address. |
| 7 | Insufficient memory or resource exhaustion. |
| 8 | Non-executable file or invalid file format. |
| 9 | Failed child process execution. |
| 18 | Connection to a remote server failed. |
| 22 | Invalid argument or faulty network connection. |
| 28 | No space left on device. |
| 35 | Timeout while establishing a connection. |
| 56 | Faulty TLS connection. |
| 60 | SSL certificate error. |
| 1 | General error / Operation not permitted |
| 2 | Misuse of shell builtins (e.g. syntax error) |
### Command Execution Errors
### curl / wget (635)
| Code | Description |
|------|-------------|
| 125 | Docker error: Container could not start. |
| 126 | Command not executable: Incorrect permissions or missing dependencies. |
| 127 | Command not found: Incorrect path or missing dependency. |
| 128 | Invalid exit signal, e.g., incorrect Git command. |
| 6 | curl: DNS resolution failed (could not resolve host) |
| 7 | curl: Failed to connect (network unreachable / host down) |
| 22 | curl: HTTP error returned (404, 429, 500+) |
| 28 | curl: Operation timeout (network slow or server not responding) |
| 35 | curl: SSL/TLS handshake failed (certificate error) |
### Signal Errors
### APT / Package Manager (100102)
| Code | Description |
|------|-------------|
| 129 | Signal 1 (SIGHUP): Process terminated due to hangup. |
| 130 | Signal 2 (SIGINT): Manual termination via Ctrl+C. |
| 132 | Signal 4 (SIGILL): Illegal machine instruction. |
| 133 | Signal 5 (SIGTRAP): Debugging error or invalid breakpoint signal. |
| 134 | Signal 6 (SIGABRT): Program aborted itself. |
| 135 | Signal 7 (SIGBUS): Memory error, invalid memory address. |
| 137 | Signal 9 (SIGKILL): Process forcibly terminated (OOM-killer or 'kill -9'). |
| 139 | Signal 11 (SIGSEGV): Segmentation fault, possibly due to invalid pointer access. |
| 141 | Signal 13 (SIGPIPE): Pipe closed unexpectedly. |
| 143 | Signal 15 (SIGTERM): Process terminated normally. |
| 152 | Signal 24 (SIGXCPU): CPU time limit exceeded. |
| 100 | APT: Package manager error (broken packages / dependency problems) |
| 101 | APT: Configuration error (bad sources.list, malformed config) |
| 102 | APT: Lock held by another process (dpkg/apt still running) |
### LXC-Specific Errors
### System / Signals (124143)
| Code | Description |
|------|-------------|
| 100 | LXC install error: Unexpected error in create_lxc.sh. |
| 101 | LXC install error: No network connection detected. |
| 200 | LXC creation failed. |
| 201 | LXC error: Invalid Storage class. |
| 202 | User aborted menu in create_lxc.sh. |
| 203 | CTID not set in create_lxc.sh. |
| 204 | PCT_OSTYPE not set in create_lxc.sh. |
| 205 | CTID cannot be less than 100 in create_lxc.sh. |
| 206 | CTID already in use in create_lxc.sh. |
| 207 | Template not found in create_lxc.sh. |
| 208 | Error downloading template in create_lxc.sh. |
| 209 | Container creation failed, but template is intact in create_lxc.sh. |
| 124 | Command timed out (timeout command) |
| 126 | Command invoked cannot execute (permission problem?) |
| 127 | Command not found |
| 128 | Invalid argument to exit |
| 130 | Terminated by Ctrl+C (SIGINT) |
| 134 | Process aborted (SIGABRT — possibly Node.js heap overflow) |
| 137 | Killed (SIGKILL / Out of memory?) |
| 139 | Segmentation fault (core dumped) |
| 141 | Broken pipe (SIGPIPE — output closed prematurely) |
| 143 | Terminated (SIGTERM) |
### Other Errors
### Systemd / Service (150154)
| Code | Description |
|------|-------------|
| 255 | Unknown critical error, often due to missing permissions or broken scripts. |
| * | Unknown error code (exit_code). |
| 150 | Systemd: Service failed to start |
| 151 | Systemd: Service unit not found |
| 152 | Permission denied (EACCES) |
| 153 | Build/compile failed (make/gcc/cmake) |
| 154 | Node.js: Native addon build failed (node-gyp) |
### Python / pip / uv (160162)
| Code | Description |
|------|-------------|
| 160 | Python: Virtualenv / uv environment missing or broken |
| 161 | Python: Dependency resolution failed |
| 162 | Python: Installation aborted (permissions or EXTERNALLY-MANAGED) |
### PostgreSQL (170173)
| Code | Description |
|------|-------------|
| 170 | PostgreSQL: Connection failed (server not running / wrong socket) |
| 171 | PostgreSQL: Authentication failed (bad user/password) |
| 172 | PostgreSQL: Database does not exist |
| 173 | PostgreSQL: Fatal error in query / syntax |
### MySQL / MariaDB (180183)
| Code | Description |
|------|-------------|
| 180 | MySQL/MariaDB: Connection failed (server not running / wrong socket) |
| 181 | MySQL/MariaDB: Authentication failed (bad user/password) |
| 182 | MySQL/MariaDB: Database does not exist |
| 183 | MySQL/MariaDB: Fatal error in query / syntax |
### MongoDB (190193)
| Code | Description |
|------|-------------|
| 190 | MongoDB: Connection failed (server not running) |
| 191 | MongoDB: Authentication failed (bad user/password) |
| 192 | MongoDB: Database not found |
| 193 | MongoDB: Fatal query error |
### Proxmox Custom Codes (200231)
| Code | Description |
|------|-------------|
| 200 | Proxmox: Failed to create lock file |
| 203 | Proxmox: Missing CTID variable |
| 204 | Proxmox: Missing PCT_OSTYPE variable |
| 205 | Proxmox: Invalid CTID (<100) |
| 206 | Proxmox: CTID already in use |
| 207 | Proxmox: Password contains unescaped special characters |
| 208 | Proxmox: Invalid configuration (DNS/MAC/Network format) |
| 209 | Proxmox: Container creation failed |
| 210 | Proxmox: Cluster not quorate |
| 211 | Proxmox: Timeout waiting for template lock |
| 212 | Proxmox: Storage type 'iscsidirect' does not support containers (VMs only) |
| 213 | Proxmox: Storage type does not support 'rootdir' content |
| 214 | Proxmox: Not enough storage space |
| 215 | Proxmox: Container created but not listed (ghost state) |
| 216 | Proxmox: RootFS entry missing in config |
| 217 | Proxmox: Storage not accessible |
| 218 | Proxmox: Template file corrupted or incomplete |
| 219 | Proxmox: CephFS does not support containers — use RBD |
| 220 | Proxmox: Unable to resolve template path |
| 221 | Proxmox: Template file not readable |
| 222 | Proxmox: Template download failed |
| 223 | Proxmox: Template not available after download |
| 224 | Proxmox: PBS storage is for backups only |
| 225 | Proxmox: No template available for OS/Version |
| 231 | Proxmox: LXC stack upgrade failed |
### Node.js / npm (243249)
| Code | Description |
|------|-------------|
| 243 | Node.js: Out of memory (JavaScript heap out of memory) |
| 245 | Node.js: Invalid command-line option |
| 246 | Node.js: Internal JavaScript Parse Error |
| 247 | Node.js: Fatal internal error |
| 248 | Node.js: Invalid C++ addon / N-API failure |
| 249 | npm/pnpm/yarn: Unknown fatal error |
### DPKG (255)
| Code | Description |
|------|-------------|
| 255 | DPKG: Fatal internal error |
### Default
| Code | Description |
|------|-------------|
| * | Unknown error |
## Environment Variable Dependencies
### Required Variables
- **`DIAGNOSTICS`**: Enable/disable diagnostic reporting ("yes"/"no")
- **`RANDOM_UUID`**: Unique identifier for tracking
- **`DIAGNOSTICS`**: Enable/disable diagnostic reporting (`"yes"` / `"no"`)
- **`RANDOM_UUID`**: Unique identifier for session tracking
### Optional Variables
- **`CT_TYPE`**: Container type (1 for LXC, 2 for VM)
- **`DISK_SIZE`**: Disk size in GB (or GB with 'G' suffix for VM)
### Container / VM Variables
- **`CT_TYPE`**: Container type (`1` for LXC, `2` for VM)
- **`DISK_SIZE`**: Disk size in GB (VMs may include `G` suffix)
- **`CORE_COUNT`**: Number of CPU cores
- **`RAM_SIZE`**: RAM size in MB
- **`var_os`**: Operating system type
- **`var_version`**: OS version
- **`DISABLEIP6`**: IPv6 disable setting
- **`NSAPP`**: Namespace application name
- **`NSAPP`**: Application name
- **`METHOD`**: Installation method
### Internal Variables
- **`POST_UPDATE_DONE`**: Prevents duplicate status updates
- **`API_URL`**: Community scripts API endpoint
- **`JSON_PAYLOAD`**: API request payload
- **`RESPONSE`**: API response
- **`DISK_SIZE_API`**: Processed disk size for VM API
- **`PB_URL`**: PocketBase server URL
- **`PB_COLLECTION`**: PocketBase collection name
- **`PB_API_URL`**: Full PocketBase API endpoint
- **`PB_RECORD_ID`**: PocketBase record ID (set after POST, used for PATCH)
- **`POST_UPDATE_DONE`**: Flag to prevent duplicate status updates
- **`JSON_PAYLOAD`**: API request payload (local to each function)
- **`RESPONSE`**: API response (local to each function)
## Error Handling Patterns
### API Communication Errors
- All API functions handle curl failures gracefully
- Network errors don't block installation process
- Missing prerequisites cause early return
- Duplicate updates are prevented
- All API functions return silently on failure — network errors never block installation
- Missing prerequisites (no curl, diagnostics disabled, no UUID) cause early return
- `POST_UPDATE_DONE` flag prevents duplicate PATCH updates
- PocketBase record lookup falls back to `GET ?filter=(random_id='...')` if `PB_RECORD_ID` is unset
### Error Description Errors
- Unknown error codes return generic message
- All error codes are handled with case statement
- Fallback message includes the actual error code
### Prerequisites Validation
- Check curl availability before API calls
- Validate DIAGNOSTICS setting
- Ensure RANDOM_UUID is set
- Check for duplicate updates
- Unknown error codes return `"Unknown error"`
- All recognized codes are handled via a `case` statement with non-overlapping ranges
- The fallback message is generic (no error code is embedded)
## Integration Examples
### With build.func
### With build.func (LXC)
```bash
#!/usr/bin/env bash
source core.func
source api.func
source build.func
# Set up API reporting
export DIAGNOSTICS="yes"
export RANDOM_UUID="$(uuidgen)"
# Report installation start
# Report LXC installation start → POST creates record
post_to_api
# Container creation...
# ... build.func code ...
# ... container creation via build.func ...
# Report completion
# Report completion → PATCH updates record
if [[ $? -eq 0 ]]; then
post_update_to_api "success" 0
post_update_to_api "done" 0
else
post_update_to_api "failed" $?
fi
```
### With vm-core.func
### With vm-core.func (VM)
```bash
#!/usr/bin/env bash
source core.func
source api.func
source vm-core.func
# Set up API reporting
export DIAGNOSTICS="yes"
export RANDOM_UUID="$(uuidgen)"
# Report VM installation start
# Report VM installation start → POST creates record
post_to_api_vm
# VM creation...
# ... vm-core.func code ...
# ... VM creation via vm-core.func ...
# Report completion
post_update_to_api "success" 0
# Report completion → PATCH updates record
post_update_to_api "done" 0
```
### With error_handler.func
@@ -397,37 +508,30 @@ source core.func
source error_handler.func
source api.func
# Use error descriptions
error_code=127
error_msg=$(get_error_description $error_code)
error_msg=$(explain_exit_code $error_code)
echo "Error $error_code: $error_msg"
# Report error to API
# Report error to PocketBase
post_update_to_api "failed" $error_code
```
## Best Practices
### API Usage
1. Always check prerequisites before API calls
2. Use unique identifiers for tracking
3. Handle API failures gracefully
4. Don't block installation on API failures
1. Always check prerequisites before API calls (handled internally by each function)
2. Call `post_to_api` / `post_to_api_vm` **once** at installation start to get a `PB_RECORD_ID`
3. Call `post_update_to_api` **once** at the end to finalize the record via PATCH
4. Never block the installation on API failures
### Error Reporting
1. Use appropriate error codes
2. Provide meaningful error descriptions
3. Report both success and failure cases
4. Prevent duplicate status updates
1. Use `explain_exit_code()` for human-readable error messages
2. Pass the actual numeric exit code to `post_update_to_api`
3. Report both success (`"done"`) and failure (`"failed"`) cases
4. The `POST_UPDATE_DONE` flag automatically prevents duplicate updates
### Diagnostic Reporting
1. Respect user privacy settings
2. Only send data when diagnostics enabled
3. Use anonymous tracking identifiers
4. Include relevant system information
### Error Handling
1. Handle unknown error codes gracefully
2. Provide fallback error messages
3. Include error code in unknown error messages
4. Use consistent error message format
1. Respect user privacy — only send data when `DIAGNOSTICS="yes"`
2. Use anonymous random UUIDs for session tracking (no personal data)
3. Include relevant system information (PVE version, OS, app name)
4. The diagnostics file at `/usr/local/community-scripts/diagnostics` controls VM reporting