ProxmoxVED/docs/build.func.md
2025-12-01 10:40:14 +01:00

585 lines
13 KiB
Markdown

# Build.func Wiki
Central LXC container build and configuration orchestration engine providing the main creation workflow, 19-step advanced wizard, defaults system, variable management, and state machine for container lifecycle.
---
## 📋 Table of Contents
- [Overview](#overview)
- [Core Functions](#core-functions)
- [Variable Management](#variable-management)
- [Build Workflow](#build-workflow)
- [Advanced Settings Wizard](#advanced-settings-wizard)
- [Defaults System](#defaults-system)
- [Best Practices](#best-practices)
- [Development Mode](#development-mode)
- [Contributing](#contributing)
---
## Overview
Build.func is the **3800+ line orchestration engine** for LXC container creation:
- ✅ 19-step interactive advanced settings wizard
- ✅ 3-tier defaults precedence system (app → user → global)
- ✅ Variable whitelisting for security
- ✅ State machine workflow management
- ✅ Container resource allocation (CPU, RAM, disk)
- ✅ Storage selection and validation
- ✅ Network configuration (bridge, MAC, VLAN, IPv6)
- ✅ Session tracking and logging
- ✅ Comprehensive pre-flight validation checks
### Execution Flow
```
Script Invocation
variables() → Initialize core variables, SESSION_ID, UUID
build.func functions sourced
Pre-flight checks (maxkeys, template availability)
Create container (pct create ...)
Network configuration
Storage tuning
Installation script execution
Completion & cleanup
```
---
## Core Functions
### `variables()`
**Purpose**: Initializes all core variables, generates unique session ID, and captures application defaults for precedence logic.
**Signature**:
```bash
variables()
```
**Parameters**: None
**Returns**: No explicit return value (sets global variables)
**Variables Initialized**:
| Variable | Source | Purpose |
|----------|--------|---------|
| `NSAPP` | `APP` converted to lowercase | Normalized app name |
| `var_install` | `${NSAPP}-install` | Installation script name |
| `PVEHOST_NAME` | `hostname` | Proxmox hostname |
| `DIAGNOSTICS` | Set to "yes" | Enable telemetry |
| `METHOD` | Set to "default" | Setup method |
| `RANDOM_UUID` | `/proc/sys/kernel/random/uuid` | Session UUID |
| `SESSION_ID` | First 8 chars of UUID | Short session ID |
| `BUILD_LOG` | `/tmp/create-lxc-${SESSION_ID}.log` | Host-side log file |
| `PVEVERSION` | `pveversion` | Proxmox VE version |
| `KERNEL_VERSION` | `uname -r` | System kernel version |
**App Default Capture** (3-tier precedence):
```bash
# Tier 1: App-declared defaults (highest priority)
APP_DEFAULT_CPU=${var_cpu:-}
APP_DEFAULT_RAM=${var_ram:-}
APP_DEFAULT_DISK=${var_disk:-}
# Tier 2: User configuration (~/.community-scripts/defaults)
# Tier 3: Global defaults (built-in)
```
**Dev Mode Setup**:
```bash
# Parse dev_mode early for special behaviors
parse_dev_mode
# If dev_mode=logs, use persistent logging location
if [[ "${DEV_MODE_LOGS}" == "true" ]]; then
mkdir -p /var/log/community-scripts
BUILD_LOG="/var/log/community-scripts/create-lxc-${SESSION_ID}-$(date +%Y%m%d_%H%M%S).log"
fi
```
**Usage Examples**:
```bash
# Example 1: Initialize with default app
APP="Jellyfin"
variables
# Result:
# NSAPP="jellyfin"
# SESSION_ID="550e8400"
# BUILD_LOG="/tmp/create-lxc-550e8400.log"
# Example 2: With dev mode
dev_mode="trace,logs"
APP="MyApp"
variables
# Result:
# Persistent logging enabled
# Bash tracing configured
# BUILD_LOG="/var/log/community-scripts/create-lxc-550e8400-20241201_103000.log"
```
---
### `maxkeys_check()`
**Purpose**: Validates kernel keyring limits don't prevent container creation (prevents "key quota exceeded" errors).
**Signature**:
```bash
maxkeys_check()
```
**Parameters**: None
**Returns**: 0 if limits acceptable; exits with error if exceeded
**Checks**:
- `/proc/sys/kernel/keys/maxkeys` - Maximum keys per user
- `/proc/sys/kernel/keys/maxbytes` - Maximum key bytes per user
- `/proc/key-users` - Current usage for UID 100000 (LXC user)
**Warning Thresholds**:
- Keys: Current >= (maxkeys - 100)
- Bytes: Current >= (maxbytes - 1000)
**Recovery Suggestions**:
```bash
# If warning triggered, suggests sysctl configuration
sysctl -w kernel.keys.maxkeys=200000
sysctl -w kernel.keys.maxbytes=40000000
# Add to persistent config
echo "kernel.keys.maxkeys=200000" >> /etc/sysctl.d/98-community-scripts.conf
sysctl -p
```
**Usage Examples**:
```bash
# Example 1: Healthy keyring usage
maxkeys_check
# Silent success: Usage is normal
# Example 2: Near limit
maxkeys_check
# Warning displayed with suggested sysctl values
# Allows continuation but recommends tuning
# Example 3: Exceeded limit
maxkeys_check
# Error: Exits with code 1
# Suggests increasing limits before retry
```
---
## Variable Management
### `default_var_settings()`
**Purpose**: Loads or creates default variable settings with 3-tier precedence.
**Signature**:
```bash
default_var_settings()
```
**Precedence Order**:
```
1. App-declared defaults (var_cpu, var_ram, var_disk from script)
2. User defaults (~/.community-scripts/defaults.sh)
3. Global built-in defaults
```
**User Defaults Location**:
```bash
~/.community-scripts/defaults.sh
```
**Example User Defaults File**:
```bash
# ~/.community-scripts/defaults.sh
CORE_COUNT=4 # Override default CPU
RAM_SIZE=4096 # Override default RAM (MB)
DISK_SIZE=32 # Override default disk (GB)
BRIDGE="vmbr0" # Preferred bridge
STORAGE="local-lvm" # Preferred storage
DISABLEIPV6="no" # Network preference
VERBOSE="no" # Output preference
```
---
### `load_vars_file()`
**Purpose**: Loads saved container variables from previous configuration.
**Signature**:
```bash
load_vars_file()
```
**Parameters**: None
**Returns**: 0 if loaded; 1 if no saved config found
**File Location**:
```bash
~/.community-scripts/${NSAPP}.vars
```
**Variables Loaded**:
- All whitelist-approved variables (CORE_COUNT, RAM_SIZE, DISK_SIZE, etc.)
- Saved settings from previous container creation
**Usage Examples**:
```bash
# Example 1: Load previous config
if load_vars_file; then
msg_ok "Loaded previous settings for $NSAPP"
else
msg_info "No previous configuration found, using defaults"
fi
# Example 2: Offer to use saved config
# Interactive: Prompts user to confirm previously saved values
```
---
### `maybe_offer_save_app_defaults()`
**Purpose**: Optionally saves current configuration for reuse in future container creations.
**Signature**:
```bash
maybe_offer_save_app_defaults()
```
**Parameters**: None
**Returns**: No explicit return value (saves or skips)
**Behavior**:
- Prompts user if they want to save current settings
- Saves to `~/.community-scripts/${NSAPP}.vars`
- User can load these settings in future runs via `load_vars_file()`
- Saves whitelisted variables only (security)
**Variables Saved**:
- CORE_COUNT, RAM_SIZE, DISK_SIZE
- BRIDGE, STORAGE, MACADDRESS
- VLAN_TAG, DISABLEIPV6
- PASSWORD settings
- Custom network configuration
**Usage Examples**:
```bash
# Example 1: After configuration
configure_container
# ... all settings done ...
maybe_offer_save_app_defaults
# Prompts: "Save these settings for future use? [y/n]"
# If yes: Saves to ~/.community-scripts/jellyfin.vars
# Example 2: Reload in next run
# User runs script again
# Prompted: "Use saved settings from last time? [y/n]"
# If yes: Load_vars_file() populates all variables
```
---
## Build Workflow
### `install_script()`
**Purpose**: Orchestrates container installation workflow inside the LXC container.
**Signature**:
```bash
install_script()
```
**Parameters**: None (uses global `NSAPP` variable)
**Returns**: 0 on success; exits with error code on failure
**Installation Steps**:
1. Copy install script into container
2. Execute via `pct exec $CTID bash /tmp/...`
3. Capture output and exit code
4. Report completion to API
5. Handle errors with cleanup
**Error Handling**:
```bash
# If installation fails:
# - Captures exit code
# - Posts failure to API (if telemetry enabled)
# - Displays error with explanation
# - Offers debug shell (if DEV_MODE_BREAKPOINT)
# - Cleans up container (unless DEV_MODE_KEEP)
```
---
## Advanced Settings Wizard
### `advanced_settings()`
**Purpose**: Interactive 19-step wizard for advanced container configuration.
**Signature**:
```bash
advanced_settings()
```
**Parameters**: None
**Returns**: No explicit return value (populates variables)
**Wizard Steps** (19 total):
1. **CPU Cores** - Allocation (1-128)
2. **RAM Size** - Allocation in MB (256-65536)
3. **Disk Size** - Allocation in GB (1-4096)
4. **Storage** - Select storage backend (local, local-lvm, etc.)
5. **Bridge** - Network bridge (vmbr0, vmbr1, etc.)
6. **MAC Address** - Custom or auto-generated
7. **VLAN Tag** - Optional VLAN configuration
8. **IPv6** - Enable/disable IPv6
9. **Disable IPV6** - Explicit disable option
10. **DHCP** - DHCP or static IP
11. **IP Configuration** - If static: IP/mask
12. **Gateway** - Network gateway
13. **DNS** - DNS server configuration
14. **Hostname** - Container hostname
15. **Root Password** - Set or leave empty (auto-login)
16. **SSH Access** - Enable root SSH
17. **Features** - FUSE, Nesting, keyctl, etc.
18. **Start on Boot** - Autostart configuration
19. **Privileged Mode** - Privileged or unprivileged container
**User Input Methods**:
- Whiptail dialogs (graphical)
- Command-line prompts (fallback)
- Validation of all inputs
- Confirmation summary before creation
**Usage Examples**:
```bash
# Example 1: Run wizard
advanced_settings
# User prompted for each of 19 settings
# Responses stored in variables
# Example 2: Scripted (skip prompts)
CORE_COUNT=4
RAM_SIZE=4096
DISK_SIZE=32
# ... set all 19 variables ...
# advanced_settings() skips prompts since variables already set
```
---
## Defaults System
### 3-Tier Precedence Logic
**Tier 1 (Highest Priority): App-Declared Defaults**
```bash
# In app script header (before default.vars sourced):
var_cpu=4
var_ram=2048
var_disk=20
# If user has higher value in tier 2/3, app value takes precedence
```
**Tier 2 (Medium Priority): User Defaults**
```bash
# In ~/.community-scripts/defaults.sh:
CORE_COUNT=6
RAM_SIZE=4096
DISK_SIZE=32
# Can be overridden by app defaults (tier 1)
```
**Tier 3 (Lowest Priority): Global Built-in Defaults**
```bash
# Built into build.func:
CORE_COUNT=2 (default)
RAM_SIZE=2048 (default, in MB)
DISK_SIZE=8 (default, in GB)
```
**Resolution Algorithm**:
```bash
# For CPU cores (example):
if [ -n "$APP_DEFAULT_CPU" ]; then
CORE_COUNT=$APP_DEFAULT_CPU # Tier 1 wins
elif [ -n "$USER_DEFAULT_CPU" ]; then
CORE_COUNT=$USER_DEFAULT_CPU # Tier 2
else
CORE_COUNT=2 # Tier 3 (global)
fi
```
---
## Best Practices
### 1. **Always Call variables() First**
```bash
#!/bin/bash
source <(curl -fsSL .../build.func)
load_functions
catch_errors
# Must be first real function call
variables
# Then safe to use SESSION_ID, BUILD_LOG, etc.
msg_info "Building container (Session: $SESSION_ID)"
```
### 2. **Declare App Defaults Before Sourcing build.func**
```bash
#!/bin/bash
# Declare app defaults BEFORE sourcing build.func
var_cpu=4
var_ram=4096
var_disk=20
source <(curl -fsSL .../build.func)
variables # These defaults are captured
# Now var_cpu, var_ram, var_disk are in APP_DEFAULT_*
```
### 3. **Use Variable Whitelisting**
```bash
# Only these variables are allowed to be saved/loaded:
WHITELIST="CORE_COUNT RAM_SIZE DISK_SIZE BRIDGE STORAGE MACADDRESS VLAN_TAG DISABLEIPV6"
# Sensitive variables are NEVER saved:
# PASSWORD, SSH keys, API tokens, etc.
```
### 4. **Check Pre-flight Conditions**
```bash
variables
maxkeys_check # Validate kernel limits
pve_check # Validate PVE version
arch_check # Validate architecture
# Only proceed after all checks pass
msg_ok "Pre-flight checks passed"
```
### 5. **Track Sessions**
```bash
# Use SESSION_ID in all logs
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log"
# Keep logs for troubleshooting
# Can be reviewed later: tail -50 /tmp/create-lxc-550e8400.log
```
---
## Development Mode
### Dev Mode Variables
Set via environment or in script:
```bash
dev_mode="trace,keep,breakpoint"
parse_dev_mode
# Enables:
# - DEV_MODE_TRACE=true (bash -x)
# - DEV_MODE_KEEP=true (never delete container)
# - DEV_MODE_BREAKPOINT=true (shell on error)
```
### Debug Container Creation
```bash
# Run with all debugging enabled
dev_mode="trace,keep,logs" bash ct/jellyfin.sh
# Then review logs:
tail -200 /var/log/community-scripts/create-lxc-*.log
# Container stays running (DEV_MODE_KEEP)
# Allows ssh inspection: ssh root@<container-ip>
```
---
## Contributing
### Adding New Wizard Steps
1. Add step number and variable to documentation
2. Add whiptail prompt in `advanced_settings()`
3. Add validation logic
4. Add to whitelist if user should save it
5. Update documentation with examples
### Extending Defaults System
To add new tier or change precedence:
1. Update 3-tier logic section
2. Modify resolution algorithm
3. Document new precedence order
4. Update whitelist accordingly
### Testing Build Workflow
```bash
# Test with dry-run mode
dev_mode="dryrun" bash ct/myapp.sh
# Shows all commands without executing
# Test with keep mode
dev_mode="keep" bash ct/myapp.sh
# Container stays if fails, allows inspection
```
---
## Notes
- Build.func is **large and complex** (3800+ lines) - handles most container creation logic
- Variables are **passed to container** via pct set/environment
- Session ID **enables request tracking** across distributed logs
- Defaults system is **flexible** (3-tier precedence)
- Pre-flight checks **prevent many common errors**