# 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@ ``` --- ## 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**