Restructure and relocate documentation files
Removed outdated documentation files from docs/. Added new detailed guides to ct/ and install/ directories. Updated README.md to reflect new navigation, learning paths, and documentation structure. Relocated system guides and technical references to settings/ and install/ subdirectories for improved organization.
This commit is contained in:
parent
3998b80194
commit
1e5627ea19
1121
docs/APP-install.md
1121
docs/APP-install.md
File diff suppressed because it is too large
Load Diff
346
docs/INDEX.md
346
docs/INDEX.md
@ -1,346 +0,0 @@
|
||||
# 📚 ProxmoxVED Documentation Index
|
||||
|
||||
Complete guide to all ProxmoxVED documentation - quickly find what you need.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Quick Navigation by Goal**
|
||||
|
||||
### 👤 **I want to...**
|
||||
|
||||
**Contribute a new application**
|
||||
→ Start with: [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md)
|
||||
→ Then: [UPDATED_APP-ct.md](UPDATED_APP-ct.md) + [UPDATED_APP-install.md](UPDATED_APP-install.md)
|
||||
|
||||
**Understand the architecture**
|
||||
→ Read: [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md)
|
||||
→ Then: [misc/README.md](misc/README.md)
|
||||
|
||||
**Debug a failed installation**
|
||||
→ Check: [EXIT_CODES.md](EXIT_CODES.md)
|
||||
→ Then: [DEV_MODE.md](DEV_MODE.md)
|
||||
→ See also: [misc/error_handler.func/](misc/error_handler.func/)
|
||||
|
||||
**Configure system defaults**
|
||||
→ Read: [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md)
|
||||
|
||||
**Learn about recent changes**
|
||||
→ Check: [CHANGELOG_MISC.md](CHANGELOG_MISC.md)
|
||||
|
||||
**Develop a function library**
|
||||
→ Study: [misc/](misc/) documentation
|
||||
|
||||
---
|
||||
|
||||
## 📂 **Documentation by Category**
|
||||
|
||||
### 🏗️ **Project Structure Documentation**
|
||||
|
||||
| Directory | Documentation |
|
||||
|-----------|---|
|
||||
| **[/ct](ct/)** | Container creation scripts documentation |
|
||||
| **[/install](install/)** | Installation scripts documentation |
|
||||
| **[/vm](vm/)** | Virtual machine creation scripts documentation |
|
||||
| **[/tools](tools/)** | Tools and utilities documentation |
|
||||
| **[/api](api/)** | API integration documentation |
|
||||
| **[/misc](misc/)** | Function libraries (9 total) |
|
||||
|
||||
### 🚀 **For Contributors**
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md) | Complete contribution workflow |
|
||||
| [UPDATED_APP-ct.md](UPDATED_APP-ct.md) | How to write ct/AppName.sh scripts |
|
||||
| [UPDATED_APP-install.md](UPDATED_APP-install.md) | How to write install/appname-install.sh scripts |
|
||||
| [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md) | System architecture deep-dive |
|
||||
|
||||
### 🔧 **For Operators & Developers**
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [EXIT_CODES.md](EXIT_CODES.md) | Complete exit code reference |
|
||||
| [DEV_MODE.md](DEV_MODE.md) | Debugging and development modes |
|
||||
| [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md) | Configuration and defaults system |
|
||||
| [CHANGELOG_MISC.md](CHANGELOG_MISC.md) | Recent changes and updates |
|
||||
|
||||
### 📚 **Function Library Documentation** (9 libraries)
|
||||
|
||||
**Core Functions**:
|
||||
- [build.func/](misc/build.func/) - Container creation orchestrator (7 files)
|
||||
- [core.func/](misc/core.func/) - Utility functions (5 files)
|
||||
- [error_handler.func/](misc/error_handler.func/) - Error handling (5 files)
|
||||
- [api.func/](misc/api.func/) - Proxmox API integration (5 files)
|
||||
|
||||
**Installation Functions**:
|
||||
- [install.func/](misc/install.func/) - Container setup (5 files)
|
||||
- [tools.func/](misc/tools.func/) - Package and tool installation (6 files)
|
||||
|
||||
**Alpine Linux Functions**:
|
||||
- [alpine-install.func/](misc/alpine-install.func/) - Alpine setup (5 files)
|
||||
- [alpine-tools.func/](misc/alpine-tools.func/) - Alpine tools (5 files)
|
||||
|
||||
**VM Functions**:
|
||||
- [cloud-init.func/](misc/cloud-init.func/) - VM provisioning (5 files)
|
||||
|
||||
---
|
||||
|
||||
## 📋 **All Documentation Files**
|
||||
|
||||
### Root Level (13 main files + 6 directory structures)
|
||||
|
||||
```
|
||||
/docs/
|
||||
├─ CONTRIBUTION_GUIDE.md (2800+ lines) Contributing guide
|
||||
├─ UPDATED_APP-ct.md (900+ lines) ct script guide
|
||||
├─ UPDATED_APP-install.md (1000+ lines) install script guide
|
||||
├─ TECHNICAL_REFERENCE.md (600+ lines) Architecture reference
|
||||
├─ DEFAULTS_SYSTEM_GUIDE.md (700+ lines) Configuration guide
|
||||
├─ CHANGELOG_MISC.md (450+ lines) Change history
|
||||
├─ EXIT_CODES.md (400+ lines) Exit codes reference
|
||||
├─ DEV_MODE.md (400+ lines) Dev mode guide
|
||||
├─ INDEX.md (This file) Documentation index
|
||||
│
|
||||
├─ ct/ README for container scripts ★ NEW
|
||||
├─ install/ README for installation scripts ★ NEW
|
||||
├─ vm/ README for VM scripts ★ NEW
|
||||
├─ tools/ README for tools & utilities ★ NEW
|
||||
├─ api/ README for API integration ★ NEW
|
||||
│
|
||||
└─ misc/ Function libraries (detailed below)
|
||||
```
|
||||
|
||||
### Project Structure Mirror with Docs (48 files in misc/)
|
||||
|
||||
Each top-level project directory (`/ct`, `/install`, `/vm`, `/tools`, `/api`) has a documentation companion in `/docs/` with a README explaining that section.
|
||||
|
||||
### misc/ Subdirectories (48 files)
|
||||
|
||||
```
|
||||
/docs/misc/
|
||||
├─ README.md (comprehensive overview)
|
||||
│
|
||||
├─ build.func/ (7 files)
|
||||
│ ├─ README.md
|
||||
│ ├─ BUILD_FUNC_FLOWCHART.md
|
||||
│ ├─ BUILD_FUNC_ARCHITECTURE.md
|
||||
│ ├─ BUILD_FUNC_ENVIRONMENT_VARIABLES.md
|
||||
│ ├─ BUILD_FUNC_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ BUILD_FUNC_EXECUTION_FLOWS.md
|
||||
│ └─ BUILD_FUNC_USAGE_EXAMPLES.md
|
||||
│
|
||||
├─ core.func/ (5 files)
|
||||
│ ├─ README.md
|
||||
│ ├─ CORE_FLOWCHART.md
|
||||
│ ├─ CORE_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ CORE_INTEGRATION.md
|
||||
│ └─ CORE_USAGE_EXAMPLES.md
|
||||
│
|
||||
├─ error_handler.func/ (5 files)
|
||||
│ ├─ README.md
|
||||
│ ├─ ERROR_HANDLER_FLOWCHART.md
|
||||
│ ├─ ERROR_HANDLER_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ ERROR_HANDLER_INTEGRATION.md
|
||||
│ └─ ERROR_HANDLER_USAGE_EXAMPLES.md
|
||||
│
|
||||
├─ api.func/ (5 files)
|
||||
│ ├─ README.md
|
||||
│ ├─ API_FLOWCHART.md
|
||||
│ ├─ API_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ API_INTEGRATION.md
|
||||
│ └─ API_USAGE_EXAMPLES.md
|
||||
│
|
||||
├─ install.func/ (5 files)
|
||||
│ ├─ README.md
|
||||
│ ├─ INSTALL_FUNC_FLOWCHART.md
|
||||
│ ├─ INSTALL_FUNC_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ INSTALL_FUNC_INTEGRATION.md
|
||||
│ └─ INSTALL_FUNC_USAGE_EXAMPLES.md
|
||||
│
|
||||
├─ tools.func/ (6 files) ★ NEW
|
||||
│ ├─ README.md
|
||||
│ ├─ TOOLS_FUNC_FLOWCHART.md
|
||||
│ ├─ TOOLS_FUNC_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ TOOLS_FUNC_INTEGRATION.md
|
||||
│ ├─ TOOLS_FUNC_USAGE_EXAMPLES.md
|
||||
│ └─ TOOLS_FUNC_ENVIRONMENT_VARIABLES.md
|
||||
│
|
||||
├─ alpine-install.func/ (5 files) ★ NEW
|
||||
│ ├─ README.md
|
||||
│ ├─ ALPINE_INSTALL_FUNC_FLOWCHART.md
|
||||
│ ├─ ALPINE_INSTALL_FUNC_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ ALPINE_INSTALL_FUNC_INTEGRATION.md
|
||||
│ └─ ALPINE_INSTALL_FUNC_USAGE_EXAMPLES.md
|
||||
│
|
||||
├─ alpine-tools.func/ (5 files) ★ NEW
|
||||
│ ├─ README.md
|
||||
│ ├─ ALPINE_TOOLS_FUNC_FLOWCHART.md
|
||||
│ ├─ ALPINE_TOOLS_FUNC_FUNCTIONS_REFERENCE.md
|
||||
│ ├─ ALPINE_TOOLS_FUNC_INTEGRATION.md
|
||||
│ └─ ALPINE_TOOLS_FUNC_USAGE_EXAMPLES.md
|
||||
│
|
||||
└─ cloud-init.func/ (5 files) ★ NEW
|
||||
├─ README.md
|
||||
├─ CLOUD_INIT_FUNC_FLOWCHART.md
|
||||
├─ CLOUD_INIT_FUNC_FUNCTIONS_REFERENCE.md
|
||||
├─ CLOUD_INIT_FUNC_INTEGRATION.md
|
||||
└─ CLOUD_INIT_FUNC_USAGE_EXAMPLES.md
|
||||
## 📊 **Documentation Statistics**
|
||||
|
||||
| Metric | Count |
|
||||
|--------|:---:|
|
||||
| Total Documentation Files | 67 |
|
||||
| Project Directories Documented | 6 (ct, install, vm, tools, api, misc) |
|
||||
| Function Libraries Documented | 9 |
|
||||
| Total Functions Referenced | 150+ |
|
||||
| Total Lines of Documentation | 15,000+ |
|
||||
| Code Examples | 50+ |
|
||||
| Visual Flowcharts | 15+ |
|
||||
|
||||
**New in this update (★ NEW)**: 6 new section directories (ct/, install/, vm/, tools/, api/) mirroring project structure
|
||||
| Code Examples | 50+ |
|
||||
| Visual Flowcharts | 15+ |
|
||||
|
||||
**New in this update (★ NEW)**: 5 new function library subdirectories with 25 files
|
||||
|
||||
---
|
||||
|
||||
## 🎓 **Learning Paths**
|
||||
|
||||
### Path 1: Beginner - First Time Contributing (2-3 hours)
|
||||
|
||||
1. Read: [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md) - Quick Start section
|
||||
2. Read: [UPDATED_APP-ct.md](UPDATED_APP-ct.md) - Overview
|
||||
3. Read: [UPDATED_APP-install.md](UPDATED_APP-install.md) - Overview
|
||||
4. Study: One real example from each guide
|
||||
5. Create your first ct/app.sh and install/app-install.sh
|
||||
6. Submit PR!
|
||||
|
||||
### Path 2: Intermediate - Deep Understanding (4-6 hours)
|
||||
|
||||
1. Read: [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md)
|
||||
2. Study: [misc/build.func/README.md](misc/build.func/README.md)
|
||||
3. Study: [misc/tools.func/README.md](misc/tools.func/README.md)
|
||||
4. Study: [misc/install.func/README.md](misc/install.func/README.md)
|
||||
5. Review: EXIT_CODES and error handling
|
||||
6. Create an advanced application with custom setup
|
||||
|
||||
### Path 3: Advanced - Architecture Mastery (8+ hours)
|
||||
|
||||
1. Read all TECHNICAL_REFERENCE.md
|
||||
2. Study all 9 function libraries in depth:
|
||||
- Flowchart
|
||||
- Functions Reference
|
||||
- Integration Guide
|
||||
- Usage Examples
|
||||
3. Review: [CHANGELOG_MISC.md](CHANGELOG_MISC.md) for recent changes
|
||||
4. Review: [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md)
|
||||
5. Study: [DEV_MODE.md](DEV_MODE.md) for debugging
|
||||
6. Contribute to function libraries or complex applications
|
||||
|
||||
### Path 4: Operator/User - Configuration Focus (1-2 hours)
|
||||
|
||||
1. Read: [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md)
|
||||
2. Read: [EXIT_CODES.md](EXIT_CODES.md) - for troubleshooting
|
||||
3. Read: [DEV_MODE.md](DEV_MODE.md) - for debugging
|
||||
|
||||
---
|
||||
|
||||
## 🔍 **Search Guide**
|
||||
|
||||
### Looking for...
|
||||
|
||||
**How do I create a ct script?**
|
||||
→ [UPDATED_APP-ct.md](UPDATED_APP-ct.md)
|
||||
|
||||
**How do I create an install script?**
|
||||
→ [UPDATED_APP-install.md](UPDATED_APP-install.md)
|
||||
|
||||
**What does exit code 206 mean?**
|
||||
→ [EXIT_CODES.md](EXIT_CODES.md#container-creation-errors-200-209)
|
||||
|
||||
**How do I debug a failed installation?**
|
||||
→ [DEV_MODE.md](DEV_MODE.md)
|
||||
|
||||
**What are the default configuration options?**
|
||||
→ [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md)
|
||||
|
||||
**What's a function in build.func?**
|
||||
→ [misc/build.func/BUILD_FUNC_FUNCTIONS_REFERENCE.md](misc/build.func/BUILD_FUNC_FUNCTIONS_REFERENCE.md)
|
||||
|
||||
**How do I install Node.js in a container?**
|
||||
→ [misc/tools.func/TOOLS_FUNC_FUNCTIONS_REFERENCE.md](misc/tools.func/TOOLS_FUNC_FUNCTIONS_REFERENCE.md#setup_nodejsversion)
|
||||
|
||||
**How do Alpine containers differ from Debian?**
|
||||
→ [misc/alpine-install.func/README.md](misc/alpine-install.func/README.md)
|
||||
|
||||
**What changed recently in /misc?**
|
||||
→ [CHANGELOG_MISC.md](CHANGELOG_MISC.md)
|
||||
|
||||
---
|
||||
|
||||
## ✅ **Documentation Completeness**
|
||||
|
||||
- ✅ All 9 function libraries have dedicated subdirectories
|
||||
- ✅ Each library has 5-6 detailed documentation files
|
||||
- ✅ Complete flowcharts for complex processes
|
||||
- ✅ Alphabetical function references with signatures
|
||||
- ✅ Real-world usage examples for every pattern
|
||||
- ✅ Integration guides showing component relationships
|
||||
- ✅ Best practices documented with DO/DON'T sections
|
||||
- ✅ Troubleshooting guides for common issues
|
||||
- ✅ Exit codes fully mapped and explained
|
||||
- ✅ Architecture documentation with diagrams
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Standardized Documentation Pattern**
|
||||
|
||||
Each function library follows this consistent pattern:
|
||||
|
||||
```
|
||||
function-library/
|
||||
├─ README.md # Quick reference
|
||||
├─ FUNCTION_LIBRARY_FLOWCHART.md # Visual flows
|
||||
├─ FUNCTION_LIBRARY_FUNCTIONS_REFERENCE.md # Complete reference
|
||||
├─ FUNCTION_LIBRARY_INTEGRATION.md # How it connects
|
||||
├─ FUNCTION_LIBRARY_USAGE_EXAMPLES.md # Real examples
|
||||
└─ [FUNCTION_LIBRARY_ENVIRONMENT_VARIABLES.md] # (if needed)
|
||||
```
|
||||
|
||||
This makes it easy to:
|
||||
- Find information quickly
|
||||
- Navigate between related docs
|
||||
- Understand component relationships
|
||||
- Learn from examples
|
||||
- Reference complete function signatures
|
||||
|
||||
---
|
||||
|
||||
## 📝 **Last Updated**
|
||||
|
||||
- **Date**: December 2025
|
||||
- **Version**: 2.0 (Comprehensive Restructure)
|
||||
- **Status**: ✅ All 9 function libraries fully documented and standardized
|
||||
- **New This Update**: tools.func/, alpine-install.func/, alpine-tools.func/, cloud-init.func/ subdirectories with complete documentation
|
||||
|
||||
---
|
||||
|
||||
## 🤝 **Contributing Documentation**
|
||||
|
||||
Found an error or want to improve documentation?
|
||||
|
||||
1. Open an issue: https://github.com/community-scripts/ProxmoxVED/issues
|
||||
2. Or submit a PR improving documentation
|
||||
3. See: [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md) for details
|
||||
|
||||
---
|
||||
|
||||
## 📚 **Related Resources**
|
||||
|
||||
- **GitHub Repository**: https://github.com/community-scripts/ProxmoxVED
|
||||
- **Proxmox Documentation**: https://pve.proxmox.com/wiki/
|
||||
- **Community Discussions**: https://github.com/community-scripts/ProxmoxVED/discussions
|
||||
|
||||
---
|
||||
|
||||
**Ready to get started?** Choose a learning path above or use the quick navigation. 🚀
|
||||
@ -1,12 +1,40 @@
|
||||
# 📚 ProxmoxVED Documentation
|
||||
|
||||
Complete documentation for the ProxmoxVED project - mirroring the project structure with comprehensive guides for every component.
|
||||
Complete guide to all ProxmoxVED documentation - quickly find what you need.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Quick Start by Role**
|
||||
## 🎯 **Quick Navigation by Goal**
|
||||
|
||||
### 👤 **I'm a...**
|
||||
### 👤 **I want to...**
|
||||
|
||||
**Contribute a new application**
|
||||
→ Start with: [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md)
|
||||
→ Then: [ct/DETAILED_GUIDE.md](ct/DETAILED_GUIDE.md) + [install/DETAILED_GUIDE.md](install/DETAILED_GUIDE.md)
|
||||
|
||||
**Understand the architecture**
|
||||
→ Read: [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md)
|
||||
→ Then: [misc/README.md](misc/README.md)
|
||||
|
||||
**Debug a failed installation**
|
||||
→ Check: [EXIT_CODES.md](EXIT_CODES.md)
|
||||
→ Then: [DEV_MODE.md](DEV_MODE.md)
|
||||
→ See also: [misc/error_handler.func/](misc/error_handler.func/)
|
||||
|
||||
**Configure system defaults**
|
||||
→ Read: [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md)
|
||||
|
||||
**Learn about recent changes**
|
||||
→ Check: [CHANGELOG_MISC.md](CHANGELOG_MISC.md)
|
||||
|
||||
**Develop a function library**
|
||||
→ Study: [misc/](misc/) documentation
|
||||
|
||||
---
|
||||
|
||||
## 👤 **Quick Start by Role**
|
||||
|
||||
### **I'm a...**
|
||||
|
||||
**New Contributor**
|
||||
→ Start: [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md)
|
||||
@ -14,12 +42,12 @@ Complete documentation for the ProxmoxVED project - mirroring the project struct
|
||||
|
||||
**Container Creator**
|
||||
→ Read: [ct/README.md](ct/README.md)
|
||||
→ Guide: [UPDATED_APP-ct.md](UPDATED_APP-ct.md)
|
||||
→ Deep Dive: [ct/DETAILED_GUIDE.md](ct/DETAILED_GUIDE.md)
|
||||
→ Reference: [misc/build.func/](misc/build.func/)
|
||||
|
||||
**Installation Script Developer**
|
||||
→ Read: [install/README.md](install/README.md)
|
||||
→ Guide: [UPDATED_APP-install.md](UPDATED_APP-install.md)
|
||||
→ Deep Dive: [install/DETAILED_GUIDE.md](install/DETAILED_GUIDE.md)
|
||||
→ Reference: [misc/tools.func/](misc/tools.func/)
|
||||
|
||||
**VM Provisioner**
|
||||
@ -45,7 +73,7 @@ Complete documentation for the ProxmoxVED project - mirroring the project struct
|
||||
|
||||
---
|
||||
|
||||
## 📁 **Documentation Structure**
|
||||
## 📂 **Documentation Structure**
|
||||
|
||||
### Project-Mirrored Directories
|
||||
|
||||
@ -53,11 +81,11 @@ Each major project directory has documentation:
|
||||
|
||||
```
|
||||
ProxmoxVED/
|
||||
├─ ct/ ↔ docs/ct/README.md
|
||||
├─ install/ ↔ docs/install/README.md
|
||||
├─ vm/ ↔ docs/vm/README.md
|
||||
├─ tools/ ↔ docs/tools/README.md
|
||||
├─ api/ ↔ docs/api/README.md
|
||||
├─ ct/ ↔ docs/ct/ (README.md + DETAILED_GUIDE.md)
|
||||
├─ install/ ↔ docs/install/ (README.md + DETAILED_GUIDE.md)
|
||||
├─ vm/ ↔ docs/vm/ (README.md)
|
||||
├─ tools/ ↔ docs/tools/ (README.md)
|
||||
├─ api/ ↔ docs/api/ (README.md)
|
||||
└─ misc/ ↔ docs/misc/ (9 function libraries)
|
||||
```
|
||||
|
||||
@ -66,8 +94,8 @@ ProxmoxVED/
|
||||
| Document | Purpose | Audience |
|
||||
|----------|---------|----------|
|
||||
| [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md) | How to contribute | Contributors |
|
||||
| [UPDATED_APP-ct.md](UPDATED_APP-ct.md) | Create ct scripts | Container developers |
|
||||
| [UPDATED_APP-install.md](UPDATED_APP-install.md) | Create install scripts | Installation developers |
|
||||
| [ct/DETAILED_GUIDE.md](ct/DETAILED_GUIDE.md) | Create ct scripts | Container developers |
|
||||
| [install/DETAILED_GUIDE.md](install/DETAILED_GUIDE.md) | Create install scripts | Installation developers |
|
||||
| [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md) | Architecture deep-dive | Architects, advanced users |
|
||||
| [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md) | Configuration system | Operators, power users |
|
||||
| [EXIT_CODES.md](EXIT_CODES.md) | Exit code reference | Troubleshooters |
|
||||
@ -83,7 +111,7 @@ Documentation for `/ct` - Container creation scripts that run on the Proxmox hos
|
||||
|
||||
**Includes**:
|
||||
- Overview of container creation process
|
||||
- Link to [UPDATED_APP-ct.md](UPDATED_APP-ct.md) guide
|
||||
- Deep dive: [DETAILED_GUIDE.md](ct/DETAILED_GUIDE.md) - Complete reference with examples
|
||||
- Reference to [misc/build.func/](misc/build.func/)
|
||||
- Quick start for creating new containers
|
||||
|
||||
@ -92,7 +120,7 @@ Documentation for `/install` - Scripts that run inside containers to install app
|
||||
|
||||
**Includes**:
|
||||
- Overview of 10-phase installation pattern
|
||||
- Link to [UPDATED_APP-install.md](UPDATED_APP-install.md) guide
|
||||
- Deep dive: [DETAILED_GUIDE.md](install/DETAILED_GUIDE.md) - Complete reference with examples
|
||||
- Reference to [misc/tools.func/](misc/tools.func/)
|
||||
- Alpine vs Debian differences
|
||||
|
||||
@ -145,13 +173,12 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
|
||||
1. [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md) - Quick Start
|
||||
2. Pick your area:
|
||||
- Containers → [ct/README.md](ct/README.md)
|
||||
- Installation → [install/README.md](install/README.md)
|
||||
- Containers → [ct/README.md](ct/README.md) + [ct/DETAILED_GUIDE.md](ct/DETAILED_GUIDE.md)
|
||||
- Installation → [install/README.md](install/README.md) + [install/DETAILED_GUIDE.md](install/DETAILED_GUIDE.md)
|
||||
- VMs → [vm/README.md](vm/README.md)
|
||||
3. Read the corresponding UPDATED_APP guide
|
||||
4. Study existing similar script
|
||||
5. Create your contribution
|
||||
6. Submit PR
|
||||
3. Study existing similar script
|
||||
4. Create your contribution
|
||||
5. Submit PR
|
||||
|
||||
### Path 2: Intermediate Developer (4-6 hours)
|
||||
|
||||
@ -167,8 +194,7 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
### Path 3: Advanced Architect (8+ hours)
|
||||
|
||||
1. All of Intermediate Path
|
||||
2. Study all 9 function libraries:
|
||||
- Each with FLOWCHART, FUNCTIONS_REFERENCE, INTEGRATION, USAGE_EXAMPLES
|
||||
2. Study all 9 function libraries in depth
|
||||
3. [DEFAULTS_SYSTEM_GUIDE.md](DEFAULTS_SYSTEM_GUIDE.md) - Configuration system
|
||||
4. [DEV_MODE.md](DEV_MODE.md) - Debugging and development
|
||||
5. Design new features or function libraries
|
||||
@ -186,7 +212,7 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
|
||||
| Metric | Count |
|
||||
|--------|:---:|
|
||||
| **Documentation Files** | 67 |
|
||||
| **Documentation Files** | 63 |
|
||||
| **Total Lines** | 15,000+ |
|
||||
| **Function Libraries** | 9 |
|
||||
| **Functions Documented** | 150+ |
|
||||
@ -200,8 +226,8 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
## 🔍 **Find It Fast**
|
||||
|
||||
### By Feature
|
||||
- **How do I create a container?** → [UPDATED_APP-ct.md](UPDATED_APP-ct.md)
|
||||
- **How do I create an install script?** → [UPDATED_APP-install.md](UPDATED_APP-install.md)
|
||||
- **How do I create a container?** → [ct/DETAILED_GUIDE.md](ct/DETAILED_GUIDE.md)
|
||||
- **How do I create an install script?** → [install/DETAILED_GUIDE.md](install/DETAILED_GUIDE.md)
|
||||
- **How do I create a VM?** → [vm/README.md](vm/README.md)
|
||||
- **How do I install Node.js?** → [misc/tools.func/](misc/tools.func/)
|
||||
- **How do I debug?** → [DEV_MODE.md](DEV_MODE.md)
|
||||
@ -230,7 +256,7 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
- ✅ **Best practices** - DO/DON'T sections throughout
|
||||
- ✅ **Learning paths** - Structured curriculum by role
|
||||
- ✅ **Quick references** - Fast lookup by error code
|
||||
- ✅ **Comprehensive index** → [INDEX.md](INDEX.md)
|
||||
- ✅ **Comprehensive navigation** - This page
|
||||
|
||||
---
|
||||
|
||||
@ -238,7 +264,7 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
|
||||
**New to ProxmoxVED?** → [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md)
|
||||
|
||||
**Looking for something specific?** → [INDEX.md](INDEX.md)
|
||||
**Looking for something specific?** → Choose your role above or browse by directory
|
||||
|
||||
**Need to debug?** → [EXIT_CODES.md](EXIT_CODES.md)
|
||||
|
||||
@ -250,7 +276,7 @@ Documentation for `/misc` - 9 core function libraries with complete references.
|
||||
|
||||
Found an error? Want to improve docs?
|
||||
|
||||
1. Open issue: https://github.com/community-scripts/ProxmoxVED/issues
|
||||
1. Open issue: [GitHub Issues](https://github.com/community-scripts/ProxmoxVED/issues)
|
||||
2. Or submit PR with improvements
|
||||
3. See [CONTRIBUTION_GUIDE.md](CONTRIBUTION_GUIDE.md) for details
|
||||
|
||||
@ -259,10 +285,10 @@ Found an error? Want to improve docs?
|
||||
## 📝 **Status**
|
||||
|
||||
- **Last Updated**: December 2025
|
||||
- **Version**: 2.1 (Project Structure Mirror)
|
||||
- **Version**: 2.3 (Consolidated & Reorganized)
|
||||
- **Completeness**: ✅ 100% - All components documented
|
||||
- **Quality**: ✅ Production-ready
|
||||
- **Examples**: ✅ 50+ tested examples
|
||||
- **Structure**: ✅ Clean and organized
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -1,651 +0,0 @@
|
||||
# Alpine-Install.func Wiki
|
||||
|
||||
A specialized module for Alpine Linux LXC container setup and configuration, providing functions for IPv6 management, network verification, OS updates, SSH configuration, timezone validation, and passwordless auto-login customization.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Initialization & Signal Handling](#initialization--signal-handling)
|
||||
- [Network & Connectivity Functions](#network--connectivity-functions)
|
||||
- [OS Configuration Functions](#os-configuration-functions)
|
||||
- [SSH & MOTD Configuration](#ssh--motd-configuration)
|
||||
- [Container Customization](#container-customization)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This module provides Alpine Linux-specific installation and configuration functions used inside LXC containers during the setup phase. Key capabilities include:
|
||||
|
||||
- ✅ IPv6 enablement/disablement with persistent configuration
|
||||
- ✅ Network connectivity verification with retry logic
|
||||
- ✅ Alpine Linux OS updates via apk package manager
|
||||
- ✅ SSH daemon and MOTD configuration
|
||||
- ✅ Passwordless root auto-login setup
|
||||
- ✅ Timezone validation for Alpine containers
|
||||
- ✅ Comprehensive error handling with signal traps
|
||||
|
||||
### Integration Pattern
|
||||
|
||||
```bash
|
||||
# Alpine container scripts load this module via curl
|
||||
source <(curl -fsSL https://git.community-scripts.org/.../alpine-install.func)
|
||||
load_functions # Initialize core utilities
|
||||
catch_errors # Setup error handling and signal traps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Initialization & Signal Handling
|
||||
|
||||
### Module Dependencies
|
||||
|
||||
The module automatically sources two required dependencies:
|
||||
|
||||
```bash
|
||||
source <(curl -fsSL .../core.func) # Color codes, icons, message functions
|
||||
source <(curl -fsSL .../error_handler.func) # Error handling and exit codes
|
||||
load_functions # Initialize color/formatting
|
||||
catch_errors # Setup trap handlers
|
||||
```
|
||||
|
||||
### Signal Trap Configuration
|
||||
|
||||
```bash
|
||||
set -Eeuo pipefail # Strict error mode
|
||||
trap 'error_handler $? $LINENO "$BASH_COMMAND"' ERR
|
||||
trap on_exit EXIT # Cleanup on exit
|
||||
trap on_interrupt INT # Handle Ctrl+C (SIGINT)
|
||||
trap on_terminate TERM # Handle SIGTERM
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Network & Connectivity Functions
|
||||
|
||||
### `verb_ip6()`
|
||||
|
||||
**Purpose**: Configures IPv6 settings and sets verbose mode based on environment variables.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
verb_ip6()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (configures system state)
|
||||
|
||||
**Environment Effects**:
|
||||
- Sets `STD` variable to control output verbosity (via `set_std_mode()`)
|
||||
- If `DISABLEIPV6=yes`: disables IPv6 system-wide via sysctl
|
||||
- Modifies `/etc/sysctl.conf` for persistent IPv6 disabled state
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
verb_ip6() {
|
||||
set_std_mode # Initialize STD="" or STD="silent"
|
||||
|
||||
if [ "$DISABLEIPV6" == "yes" ]; then
|
||||
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
||||
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
|
||||
$STD rc-update add sysctl default
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: With IPv6 disabled
|
||||
DISABLEIPV6="yes"
|
||||
VERBOSE="no"
|
||||
verb_ip6
|
||||
# Result: IPv6 disabled, changes persisted to sysctl.conf
|
||||
|
||||
# Example 2: Keep IPv6 enabled (default)
|
||||
DISABLEIPV6="no"
|
||||
verb_ip6
|
||||
# Result: IPv6 remains enabled, no configuration changes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `setting_up_container()`
|
||||
|
||||
**Purpose**: Verifies network connectivity by checking for assigned IP addresses and retrying if necessary.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
setting_up_container()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global `RETRY_NUM` and `RETRY_EVERY`)
|
||||
|
||||
**Returns**: 0 on success; exits with code 1 if network unavailable after retries
|
||||
|
||||
**Environment Side Effects**:
|
||||
- Requires: `RETRY_NUM` (max attempts, default: 10), `RETRY_EVERY` (seconds between retries, default: 3)
|
||||
- Uses: `CROSS`, `RD`, `CL`, `GN`, `BL` color variables from core.func
|
||||
- Calls: `msg_info()`, `msg_ok()` message functions
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
setting_up_container() {
|
||||
msg_info "Setting up Container OS"
|
||||
i=$RETRY_NUM # Use global counter
|
||||
while [ $i -gt 0 ]; do
|
||||
# Check for non-loopback IPv4 address
|
||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | ...)" != "" ]; then
|
||||
break
|
||||
fi
|
||||
echo 1>&2 -en "${CROSS}${RD} No Network! "
|
||||
sleep $RETRY_EVERY
|
||||
i=$((i - 1))
|
||||
done
|
||||
|
||||
# If still no network after retries, exit with error
|
||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | ...)" = "" ]; then
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | ...)${CL}"
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Network available immediately
|
||||
RETRY_NUM=10
|
||||
RETRY_EVERY=3
|
||||
setting_up_container
|
||||
# Output:
|
||||
# ℹ️ Setting up Container OS
|
||||
# ✔️ Set up Container OS
|
||||
# ✔️ Network Connected: 10.0.3.50
|
||||
|
||||
# Example 2: Network delayed by 6 seconds (2 retries)
|
||||
# Script waits 3 seconds x 2, then succeeds
|
||||
# Output shows retry messages, then success
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `network_check()`
|
||||
|
||||
**Purpose**: Comprehensive network connectivity verification for both IPv4 and IPv6, including DNS resolution checks for Git-related domains.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
network_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 on success; exits with code 1 if DNS critical failure
|
||||
|
||||
**Environment Side Effects**:
|
||||
- Temporarily disables error trap (`set +e`, `trap - ERR`)
|
||||
- Modifies error handling to allow graceful failure detection
|
||||
- Re-enables error trap at end of function
|
||||
- Calls: `msg_ok()`, `msg_error()`, `fatal()` message functions
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
network_check() {
|
||||
set +e
|
||||
trap - ERR
|
||||
|
||||
# Test IPv4 via multiple DNS servers
|
||||
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ...; then
|
||||
ipv4_status="${GN}✔${CL} IPv4"
|
||||
else
|
||||
ipv4_status="${RD}✖${CL} IPv4"
|
||||
# Prompt user to continue without internet
|
||||
fi
|
||||
|
||||
# Verify DNS resolution for GitHub domains
|
||||
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
||||
if [[ -z "$RESOLVEDIP" ]]; then
|
||||
msg_error "Internet: ${ipv4_status} DNS Failed"
|
||||
else
|
||||
msg_ok "Internet: ${ipv4_status} DNS: ${BL}${RESOLVEDIP}${CL}"
|
||||
fi
|
||||
|
||||
set -e
|
||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Good connectivity
|
||||
network_check
|
||||
# Output:
|
||||
# ✔️ Network Connected: IPv4
|
||||
# ✔️ Internet: ✔ IPv4 DNS: 140.82.113.3
|
||||
|
||||
# Example 2: No internet, user continues anyway
|
||||
# Output prompts: "Internet NOT connected. Continue anyway? <y/N>"
|
||||
# If user enters 'y':
|
||||
# ⚠️ Expect Issues Without Internet
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## OS Configuration Functions
|
||||
|
||||
### `update_os()`
|
||||
|
||||
**Purpose**: Updates Alpine Linux OS packages and installs Alpine-specific tools library for additional setup functions.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
update_os()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (updates system)
|
||||
|
||||
**Environment Side Effects**:
|
||||
- Runs `apk update && apk upgrade`
|
||||
- Sources alpine-tools.func for Alpine-specific package installation helpers
|
||||
- Uses `$STD` wrapper to suppress output unless `VERBOSE=yes`
|
||||
- Calls: `msg_info()`, `msg_ok()` message functions
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
update_os() {
|
||||
msg_info "Updating Container OS"
|
||||
$STD apk update && $STD apk upgrade
|
||||
source <(curl -fsSL https://git.community-scripts.org/.../alpine-tools.func)
|
||||
msg_ok "Updated Container OS"
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Standard update
|
||||
VERBOSE="no"
|
||||
update_os
|
||||
# Output:
|
||||
# ℹ️ Updating Container OS
|
||||
# ✔️ Updated Container OS
|
||||
# (Output suppressed via $STD)
|
||||
|
||||
# Example 2: Verbose mode
|
||||
VERBOSE="yes"
|
||||
update_os
|
||||
# Output shows all apk operations plus success message
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSH & MOTD Configuration
|
||||
|
||||
### `motd_ssh()`
|
||||
|
||||
**Purpose**: Configures Message of the Day (MOTD) with container information and enables SSH root access if required.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
motd_ssh()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (configures system)
|
||||
|
||||
**Environment Side Effects**:
|
||||
- Modifies `/root/.bashrc` to set TERM environment variable
|
||||
- Creates `/etc/profile.d/00_lxc-details.sh` with container information script
|
||||
- If `SSH_ROOT=yes`: modifies `/etc/ssh/sshd_config` and starts SSH daemon
|
||||
- Uses: `APPLICATION`, `SSH_ROOT` variables from environment
|
||||
- Requires: color variables (`BOLD`, `YW`, `RD`, `GN`, `CL`) from core.func
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
motd_ssh() {
|
||||
# Configure TERM for better terminal support
|
||||
echo "export TERM='xterm-256color'" >>/root/.bashrc
|
||||
|
||||
# Gather OS information
|
||||
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
|
||||
|
||||
# Create MOTD script with container details
|
||||
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
|
||||
cat > "$PROFILE_FILE" <<'EOF'
|
||||
echo -e ""
|
||||
echo -e "${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}"
|
||||
echo -e "${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}"
|
||||
echo -e "${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}"
|
||||
echo -e "${YW} Hostname: ${GN}$(hostname)${CL}"
|
||||
echo -e "${YW} IP Address: ${GN}${IP}${CL}"
|
||||
echo -e "${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}"
|
||||
echo ""
|
||||
EOF
|
||||
|
||||
# Enable SSH root access if configured
|
||||
if [[ "${SSH_ROOT}" == "yes" ]]; then
|
||||
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
|
||||
rc-update add sshd
|
||||
/etc/init.d/sshd start
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: MOTD configuration with SSH enabled
|
||||
APPLICATION="MyApp"
|
||||
SSH_ROOT="yes"
|
||||
motd_ssh
|
||||
# Result: SSH daemon started and set to auto-start, MOTD shows app info
|
||||
|
||||
# Example 2: MOTD only (SSH disabled)
|
||||
APPLICATION="MyApp"
|
||||
SSH_ROOT="no"
|
||||
motd_ssh
|
||||
# Result: MOTD configured but SSH remains disabled
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Container Customization
|
||||
|
||||
### `validate_tz()`
|
||||
|
||||
**Purpose**: Validates that a timezone string exists in the Alpine Linux timezone database.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
validate_tz()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Timezone string (e.g., "America/New_York", "UTC", "Europe/London")
|
||||
|
||||
**Returns**: 0 if timezone file exists, 1 if invalid
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
validate_tz() {
|
||||
[[ -f "/usr/share/zoneinfo/$1" ]] # Bash test operator returns success/failure
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Valid timezone
|
||||
validate_tz "America/New_York"
|
||||
echo $? # Output: 0
|
||||
|
||||
# Example 2: Invalid timezone
|
||||
validate_tz "Invalid/Timezone"
|
||||
echo $? # Output: 1
|
||||
|
||||
# Example 3: UTC (always valid)
|
||||
validate_tz "UTC"
|
||||
echo $? # Output: 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `customize()`
|
||||
|
||||
**Purpose**: Configures container for passwordless root auto-login and creates update script for easy application re-deployment.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
customize()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global `PASSWORD` and `app` variables)
|
||||
|
||||
**Returns**: No explicit return value (configures system)
|
||||
|
||||
**Environment Side Effects**:
|
||||
- If `PASSWORD=""` (empty):
|
||||
* Removes password prompt from root login
|
||||
* Drops user into shell automatically
|
||||
* Creates autologin boot script at `/etc/local.d/autologin.start`
|
||||
* Creates `.hushlogin` to suppress login banners
|
||||
* Registers script with rc-update
|
||||
- Creates `/usr/bin/update` script for application updates
|
||||
- Requires: `app` variable (application name in lowercase)
|
||||
- Calls: `msg_info()`, `msg_ok()` message functions
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
customize() {
|
||||
if [[ "$PASSWORD" == "" ]]; then
|
||||
msg_info "Customizing Container"
|
||||
|
||||
# Remove password requirement
|
||||
passwd -d root >/dev/null 2>&1
|
||||
|
||||
# Install util-linux if needed
|
||||
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
|
||||
|
||||
# Create autologin startup script
|
||||
mkdir -p /etc/local.d
|
||||
cat > /etc/local.d/autologin.start <<'EOF'
|
||||
#!/bin/sh
|
||||
sed -i 's|^tty1::respawn:.*|tty1::respawn:/sbin/agetty --autologin root --noclear tty1 38400 linux|' /etc/inittab
|
||||
kill -HUP 1
|
||||
EOF
|
||||
chmod +x /etc/local.d/autologin.start
|
||||
touch /root/.hushlogin
|
||||
|
||||
rc-update add local >/dev/null 2>&1
|
||||
/etc/local.d/autologin.start
|
||||
|
||||
msg_ok "Customized Container"
|
||||
fi
|
||||
|
||||
# Create update script
|
||||
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
|
||||
chmod +x /usr/bin/update
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Passwordless auto-login
|
||||
PASSWORD=""
|
||||
app="myapp"
|
||||
customize
|
||||
# Result: Root login without password, auto-login configured
|
||||
# User can type: /usr/bin/update to re-run application setup
|
||||
|
||||
# Example 2: Password-protected login
|
||||
PASSWORD="MySecurePassword"
|
||||
customize
|
||||
# Result: Auto-login skipped, password remains active
|
||||
# Update script still created for re-deployment
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Initialization Order**
|
||||
|
||||
Always follow this sequence in Alpine install scripts:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
set -Eeuo pipefail
|
||||
|
||||
# 1. Ensure curl is available for sourcing functions
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
apk update && apk add curl >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# 2. Source dependencies in correct order
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
|
||||
# 3. Initialize function libraries
|
||||
load_functions # Sets up colors, formatting, icons
|
||||
catch_errors # Configures error traps and signal handlers
|
||||
|
||||
# 4. Now safe to call alpine-install.func functions
|
||||
verb_ip6
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
```
|
||||
|
||||
### 2. **Signal Handling**
|
||||
|
||||
Alpine-install.func provides comprehensive signal trap setup:
|
||||
|
||||
```bash
|
||||
# ERR trap: Catches all command failures
|
||||
trap 'error_handler $? $LINENO "$BASH_COMMAND"' ERR
|
||||
|
||||
# EXIT trap: Cleanup on normal or abnormal termination
|
||||
trap on_exit EXIT
|
||||
|
||||
# INT trap: Handle Ctrl+C gracefully
|
||||
trap on_interrupt INT
|
||||
|
||||
# TERM trap: Handle SIGTERM signal
|
||||
trap on_terminate TERM
|
||||
```
|
||||
|
||||
### 3. **Network Configuration**
|
||||
|
||||
Use retry logic when network may not be immediately available:
|
||||
|
||||
```bash
|
||||
setting_up_container # Retries up to RETRY_NUM times
|
||||
network_check # Validates DNS and Internet
|
||||
```
|
||||
|
||||
### 4. **IPv6 Considerations**
|
||||
|
||||
For production Alpine containers:
|
||||
|
||||
```bash
|
||||
# Disable IPv6 if not needed (reduces attack surface)
|
||||
DISABLEIPV6="yes"
|
||||
verb_ip6
|
||||
|
||||
# Or keep enabled (default):
|
||||
DISABLEIPV6="no"
|
||||
# No configuration needed
|
||||
```
|
||||
|
||||
### 5. **Error Handling with Color Output**
|
||||
|
||||
Functions use color-coded message output:
|
||||
|
||||
```bash
|
||||
msg_info # Informational messages (yellow)
|
||||
msg_ok # Success messages (green)
|
||||
msg_error # Error messages (red)
|
||||
msg_warn # Warning messages (orange)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
The module implements comprehensive error handling:
|
||||
|
||||
### Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success |
|
||||
| 1 | General error (network unavailable, DNS failed, etc.) |
|
||||
| 130 | Interrupted by user (SIGINT) |
|
||||
| 143 | Terminated by signal (SIGTERM) |
|
||||
|
||||
### Error Handler Function
|
||||
|
||||
The error_handler receives three parameters:
|
||||
|
||||
```bash
|
||||
error_handler() {
|
||||
local exit_code="$1" # Exit code from failed command
|
||||
local line_number="$2" # Line where error occurred
|
||||
local command="$3" # Command that failed
|
||||
|
||||
# Errors are reported with line number and command details
|
||||
# Stack trace available for debugging
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Variables
|
||||
|
||||
Available for troubleshooting:
|
||||
|
||||
```bash
|
||||
$VERBOSE # Set to "yes" to show all output
|
||||
$DEV_MODE_TRACE # Set to "true" for bash -x tracing
|
||||
$DEV_MODE_LOGS # Set to "true" to persist logs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Functions
|
||||
|
||||
When adding Alpine-specific functions:
|
||||
|
||||
1. Follow the established naming convention: `function_purpose()`
|
||||
2. Include comprehensive docstring with signature, parameters, returns
|
||||
3. Use color variables from core.func for output consistency
|
||||
4. Handle errors via error_handler trap
|
||||
5. Document all environment variable dependencies
|
||||
|
||||
### Testing New Functions
|
||||
|
||||
```bash
|
||||
# Test function in isolation with error traps:
|
||||
set -Eeuo pipefail
|
||||
trap 'error_handler $? $LINENO "$BASH_COMMAND"' ERR
|
||||
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
|
||||
# Now test your function:
|
||||
your_function
|
||||
```
|
||||
|
||||
### Compatibility
|
||||
|
||||
- Alpine Linux 3.16+ (uses ash shell compatible syntax)
|
||||
- OpenRC init system (rc-update, rc-service)
|
||||
- Requires: core.func, error_handler.func
|
||||
- Optional: alpine-tools.func (for extended package management)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Functions are designed for execution **inside** LXC containers (not on Proxmox host)
|
||||
- Alpine uses `apk` package manager (not `apt`)
|
||||
- Alpine uses OpenRC (not systemd) - use `rc-update` and `/etc/init.d/` commands
|
||||
- IPv6 can be disabled for security/performance but is enabled by default
|
||||
- Auto-login configuration persists across container reboots via rc-update
|
||||
|
||||
@ -1,588 +0,0 @@
|
||||
# Alpine-Tools.func Wiki
|
||||
|
||||
Alpine Linux-specific tool setup and package management module providing helper functions optimized for Alpine's apk package manager and minimal container environment.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Helper Functions](#helper-functions)
|
||||
- [GitHub Release Functions](#github-release-functions)
|
||||
- [Tool Installation Patterns](#tool-installation-patterns)
|
||||
- [Package Management](#package-management)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Debugging](#debugging)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Alpine-tools.func provides **Alpine Linux-specific utilities**:
|
||||
|
||||
- ✅ Alpine apk package manager wrapper
|
||||
- ✅ GitHub release version checking and installation
|
||||
- ✅ Tool caching and version tracking
|
||||
- ✅ Progress reporting with pv (pipe viewer)
|
||||
- ✅ Network resolution helpers for Alpine
|
||||
- ✅ PATH persistence across sessions
|
||||
- ✅ Retry logic for failed downloads
|
||||
- ✅ Minimal dependencies philosophy (Alpine ~5MB containers)
|
||||
|
||||
### Key Differences from Debian/Ubuntu
|
||||
|
||||
| Feature | Alpine | Debian/Ubuntu |
|
||||
|---------|--------|---------------|
|
||||
| Package Manager | apk | apt-get, dpkg |
|
||||
| Shell | ash (dash variant) | bash |
|
||||
| Init System | OpenRC | systemd |
|
||||
| Size | ~5MB base | ~100MB+ base |
|
||||
| Libc | musl | glibc |
|
||||
| Find getent | Not installed | Installed |
|
||||
|
||||
### Integration Pattern
|
||||
|
||||
```bash
|
||||
#!/bin/sh # Alpine uses ash, not bash
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../alpine-tools.func)
|
||||
load_functions
|
||||
|
||||
# Now Alpine-specific tool functions available
|
||||
need_tool curl jq # Install if missing
|
||||
check_for_gh_release "myapp" "owner/repo"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### `lower()`
|
||||
|
||||
**Purpose**: Converts string to lowercase (portable ash function).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
lower()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - String to convert
|
||||
|
||||
**Returns**: Lowercase string on stdout
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# Alpine's tr works with character classes
|
||||
printf '%s' "$1" | tr '[:upper:]' '[:lower:]'
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: App name normalization
|
||||
result=$(lower "MyApp")
|
||||
echo "$result" # Output: myapp
|
||||
|
||||
# Example 2: In variable assignment
|
||||
app_dir=$(lower "$APPLICATION")
|
||||
mkdir -p /opt/$app_dir
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `has()`
|
||||
|
||||
**Purpose**: Checks if command is available in PATH.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
has()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Command name
|
||||
|
||||
**Returns**: 0 if available, 1 if not
|
||||
|
||||
**Implementation**:
|
||||
```bash
|
||||
has() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Check availability
|
||||
if has jq; then
|
||||
echo "jq is installed"
|
||||
else
|
||||
echo "jq is not installed"
|
||||
fi
|
||||
|
||||
# Example 2: In conditionals
|
||||
has docker && docker ps || echo "Docker not installed"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `need_tool()`
|
||||
|
||||
**Purpose**: Ensures specified tools are installed, installs missing ones via apk.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
need_tool()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$@` - Tool names (space-separated)
|
||||
|
||||
**Returns**: 0 on success, 1 if installation failed
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# Checks each tool
|
||||
# If any missing: runs apk add for all
|
||||
# Displays message before and after
|
||||
```
|
||||
|
||||
**Error Handling**:
|
||||
- Returns 1 if apk add fails
|
||||
- Shows which tools failed
|
||||
- Suggests checking package names
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Ensure common tools available
|
||||
need_tool curl jq unzip git
|
||||
# Installs any missing packages
|
||||
|
||||
# Example 2: Optional tool check
|
||||
if need_tool myapp-cli; then
|
||||
myapp-cli --version
|
||||
else
|
||||
echo "myapp-cli not available in apk"
|
||||
fi
|
||||
|
||||
# Example 3: With error handling
|
||||
need_tool docker || {
|
||||
echo "Failed to install docker"
|
||||
exit 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `net_resolves()`
|
||||
|
||||
**Purpose**: Checks if hostname resolves and responds (Alpine-friendly DNS test).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
net_resolves()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Hostname to test
|
||||
|
||||
**Returns**: 0 if resolves and responds, 1 if fails
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# Alpine doesn't have getent by default
|
||||
# Falls back to nslookup if ping fails
|
||||
# Returns success if either works
|
||||
|
||||
ping -c1 -W1 "$host" >/dev/null 2>&1 || nslookup "$host" >/dev/null 2>&1
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Test GitHub connectivity
|
||||
if net_resolves api.github.com; then
|
||||
echo "Can reach GitHub API"
|
||||
else
|
||||
echo "GitHub API unreachable"
|
||||
fi
|
||||
|
||||
# Example 2: In download function
|
||||
net_resolves download.example.com || {
|
||||
echo "Download server not reachable"
|
||||
exit 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `ensure_usr_local_bin_persist()`
|
||||
|
||||
**Purpose**: Ensures `/usr/local/bin` is in PATH across all shell sessions.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
ensure_usr_local_bin_persist()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (modifies system)
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# Creates /etc/profile.d/10-localbin.sh
|
||||
# Script adds /usr/local/bin to PATH if not already present
|
||||
# Runs on every shell startup
|
||||
|
||||
# Alpine uses /etc/profile for login shells
|
||||
# profile.d scripts sourced automatically
|
||||
```
|
||||
|
||||
**Implementation**:
|
||||
```bash
|
||||
PROFILE_FILE="/etc/profile.d/10-localbin.sh"
|
||||
if [ ! -f "$PROFILE_FILE" ]; then
|
||||
echo 'case ":$PATH:" in *:/usr/local/bin:*) ;; *) export PATH="/usr/local/bin:$PATH";; esac' > "$PROFILE_FILE"
|
||||
chmod +x "$PROFILE_FILE"
|
||||
fi
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Make sure local tools available
|
||||
ensure_usr_local_bin_persist
|
||||
# Now /usr/local/bin binaries always in PATH
|
||||
|
||||
# Example 2: After installing custom tool
|
||||
cp ./my-tool /usr/local/bin/
|
||||
ensure_usr_local_bin_persist
|
||||
# Tool immediately accessible in PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `download_with_progress()`
|
||||
|
||||
**Purpose**: Downloads file with progress bar (if pv available) or simple # progress.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
download_with_progress()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - URL to download
|
||||
- `$2` - Destination file path
|
||||
|
||||
**Returns**: 0 on success, 1 on failure
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# Attempts to get content-length header
|
||||
# If available: pipes through pv for progress bar
|
||||
# If not: uses curl's built-in # progress
|
||||
# Shows errors clearly
|
||||
```
|
||||
|
||||
**Requirements**:
|
||||
- `curl` - For downloading
|
||||
- `pv` - Optional, for progress bar
|
||||
- Destination directory must exist
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Simple download
|
||||
download_with_progress "https://example.com/file.tar.gz" "/tmp/file.tar.gz"
|
||||
# Shows progress bar if pv available
|
||||
|
||||
# Example 2: With error handling
|
||||
if download_with_progress "$URL" "$DEST"; then
|
||||
echo "Downloaded successfully"
|
||||
tar -xzf "$DEST"
|
||||
else
|
||||
echo "Download failed"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GitHub Release Functions
|
||||
|
||||
### `check_for_gh_release()`
|
||||
|
||||
**Purpose**: Checks GitHub releases for available updates and compares with currently installed version.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
check_for_gh_release()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Application name (e.g., "nodejs")
|
||||
- `$2` - GitHub repository (e.g., "nodejs/node")
|
||||
- `$3` - Pinned version (optional, e.g., "20.0.0")
|
||||
|
||||
**Returns**: 0 if update needed, 1 if current or pinned
|
||||
|
||||
**Environment Variables Set**:
|
||||
- `CHECK_UPDATE_RELEASE` - Latest available version (without v prefix)
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# 1. Check network to api.github.com
|
||||
# 2. Fetch latest release tag via GitHub API
|
||||
# 3. Compare with installed version (stored in ~/.appname)
|
||||
# 4. Show appropriate message:
|
||||
# - "app pinned to vX.X.X (no update)"
|
||||
# - "app pinned vX.X.X (upstream vY.Y.Y) → update/downgrade"
|
||||
# - "Update available: vA.A.A → vB.B.B"
|
||||
# - "Already up to date"
|
||||
```
|
||||
|
||||
**File Storage**:
|
||||
```bash
|
||||
~/.${app_lc} # File contains current version string
|
||||
# Example: ~/.nodejs contains "20.10.0"
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Check for update
|
||||
check_for_gh_release "nodejs" "nodejs/node"
|
||||
# Output: "Update available: v18.0.0 → v20.10.0"
|
||||
# Sets: CHECK_UPDATE_RELEASE="20.10.0"
|
||||
|
||||
# Example 2: Pinned version (no update)
|
||||
check_for_gh_release "nodejs" "nodejs/node" "20.0.0"
|
||||
# Output: "app pinned to v20.0.0 (no update)"
|
||||
# Returns 1 (no update available)
|
||||
|
||||
# Example 3: With error handling
|
||||
if check_for_gh_release "myapp" "owner/myapp"; then
|
||||
echo "Update available: $CHECK_UPDATE_RELEASE"
|
||||
download_and_install
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tool Installation Patterns
|
||||
|
||||
### Pattern 1: Simple Package Installation
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
need_tool curl jq # Ensure tools available
|
||||
# Continue with script
|
||||
```
|
||||
|
||||
### Pattern 2: GitHub Release Installation
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
source <(curl -fsSL .../alpine-tools.func)
|
||||
load_functions
|
||||
|
||||
# Check for updates
|
||||
check_for_gh_release "myapp" "owner/myapp"
|
||||
|
||||
# Download from GitHub releases
|
||||
RELEASE="$CHECK_UPDATE_RELEASE"
|
||||
URL="https://github.com/owner/myapp/releases/download/v${RELEASE}/myapp-alpine.tar.gz"
|
||||
|
||||
download_with_progress "$URL" "/tmp/myapp-${RELEASE}.tar.gz"
|
||||
tar -xzf "/tmp/myapp-${RELEASE}.tar.gz" -C /usr/local/bin/
|
||||
```
|
||||
|
||||
### Pattern 3: Version Pinning
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# For specific use case, pin to known good version
|
||||
check_for_gh_release "nodejs" "nodejs/node" "20.10.0"
|
||||
# Will use 20.10.0 even if 21.0.0 available
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Package Management
|
||||
|
||||
### Alpine Package Naming
|
||||
|
||||
Alpine packages often have different names than Debian:
|
||||
|
||||
| Tool | Alpine | Debian |
|
||||
|------|--------|--------|
|
||||
| curl | curl | curl |
|
||||
| Git | git | git |
|
||||
| Docker | docker | docker.io |
|
||||
| PostgreSQL | postgresql-client | postgresql-client |
|
||||
| Build tools | build-base | build-essential |
|
||||
| Development headers | -dev packages | -dev packages |
|
||||
|
||||
### Finding Alpine Packages
|
||||
|
||||
```bash
|
||||
# Search for package
|
||||
apk search myapp
|
||||
|
||||
# Show package info
|
||||
apk info -d myapp
|
||||
|
||||
# List available versions
|
||||
apk search myapp --all
|
||||
```
|
||||
|
||||
### Installing Alpine Packages
|
||||
|
||||
```bash
|
||||
# Basic install (not cached)
|
||||
apk add curl git
|
||||
|
||||
# Install with --no-cache (for containers)
|
||||
apk add --no-cache curl git
|
||||
|
||||
# Force broken packages (last resort)
|
||||
apk add --no-cache --force-broken-world util-linux
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Use `--no-cache` in Containers**
|
||||
|
||||
```bash
|
||||
# Good: Saves space in container
|
||||
apk add --no-cache curl git
|
||||
|
||||
# Avoid: Wastes space
|
||||
apk update && apk add curl git
|
||||
```
|
||||
|
||||
### 2. **Check Tools Before Using**
|
||||
|
||||
```bash
|
||||
# Good: Graceful error
|
||||
if ! has jq; then
|
||||
need_tool jq || exit 1
|
||||
fi
|
||||
|
||||
# Using jq safely
|
||||
jq . < input.json
|
||||
```
|
||||
|
||||
### 3. **Use need_tool() for Multiple**
|
||||
|
||||
```bash
|
||||
# Good: Install all at once
|
||||
need_tool curl jq git unzip
|
||||
|
||||
# Less efficient: Individual checks
|
||||
has curl || apk add curl
|
||||
has jq || apk add jq
|
||||
```
|
||||
|
||||
### 4. **Ensure Persistence**
|
||||
|
||||
```bash
|
||||
# For custom tools in /usr/local/bin
|
||||
ensure_usr_local_bin_persist
|
||||
|
||||
# Now available in all future shells
|
||||
/usr/local/bin/my-custom-tool
|
||||
```
|
||||
|
||||
### 5. **Handle Network Failures**
|
||||
|
||||
```bash
|
||||
# Alpine often in isolated environments
|
||||
if ! net_resolves api.github.com; then
|
||||
echo "GitHub API unreachable"
|
||||
# Fallback to local package or error
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Check Package Availability
|
||||
|
||||
```bash
|
||||
# List all available packages
|
||||
apk search --all
|
||||
|
||||
# Find package by keyword
|
||||
apk search curl
|
||||
|
||||
# Get specific package info
|
||||
apk info postgresql-client
|
||||
```
|
||||
|
||||
### Verify Installation
|
||||
|
||||
```bash
|
||||
# Check if tool installed
|
||||
apk info | grep myapp
|
||||
|
||||
# Verify PATH
|
||||
which curl
|
||||
echo $PATH
|
||||
```
|
||||
|
||||
### Network Testing
|
||||
|
||||
```bash
|
||||
# Test DNS
|
||||
nslookup api.github.com
|
||||
|
||||
# Test connectivity
|
||||
ping -c1 1.1.1.1
|
||||
|
||||
# Test download
|
||||
curl -I https://api.github.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Helper Functions
|
||||
|
||||
When adding Alpine-specific helpers:
|
||||
|
||||
1. Use POSIX shell (ash-compatible)
|
||||
2. Avoid bash-isms
|
||||
3. Include error handling
|
||||
4. Document with examples
|
||||
5. Test on actual Alpine container
|
||||
|
||||
### Improving Package Installation
|
||||
|
||||
New patterns could support:
|
||||
- Automatic Alpine version detection
|
||||
- Package version pinning
|
||||
- Dependency resolution
|
||||
- Conflict detection
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Alpine uses **ash shell** (POSIX-compatible, not bash)
|
||||
- Alpine **apk is fast** and has minimal overhead
|
||||
- Alpine containers **~5MB base image** (vs 100MB+ for Debian)
|
||||
- **No getent available** by default (use nslookup fallback)
|
||||
- GitHub releases can be **pre-compiled for Alpine musl**
|
||||
|
||||
670
docs/api.func.md
670
docs/api.func.md
@ -1,670 +0,0 @@
|
||||
# API.func Wiki
|
||||
|
||||
A telemetry and diagnostics module providing anonymous statistics collection and API integration with the Community-Scripts infrastructure for tracking container/VM creation metrics and installation success/failure data.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Exit Code Reference](#exit-code-reference)
|
||||
- [Telemetry Functions](#telemetry-functions)
|
||||
- [API Payload Structure](#api-payload-structure)
|
||||
- [Privacy & Opt-Out](#privacy--opt-out)
|
||||
- [Error Mapping](#error-mapping)
|
||||
- [Best Practices](#best-practices)
|
||||
- [API Integration](#api-integration)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The API.func module provides anonymous telemetry reporting to Community-Scripts infrastructure, enabling:
|
||||
|
||||
- ✅ Container/VM creation statistics collection
|
||||
- ✅ Installation success/failure tracking
|
||||
- ✅ Comprehensive exit code mapping and explanation
|
||||
- ✅ Anonymous session-based tracking (UUID)
|
||||
- ✅ Privacy-respecting data collection (no personal data)
|
||||
- ✅ Opt-out capability via DIAGNOSTICS setting
|
||||
- ✅ Consistent error reporting across all scripts
|
||||
|
||||
### Integration Points
|
||||
|
||||
```bash
|
||||
# In container build scripts (on Proxmox host):
|
||||
source <(curl -fsSL .../api.func)
|
||||
post_to_api # Report container creation
|
||||
post_update_to_api # Report installation completion
|
||||
|
||||
# Error handling (in all scripts):
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
# explain_exit_code shared for consistent mappings
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
Container/VM Creation
|
||||
↓
|
||||
post_to_api()
|
||||
↓
|
||||
Community-Scripts API
|
||||
↓
|
||||
Anonymous Statistics
|
||||
(No personal data)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exit Code Reference
|
||||
|
||||
### Category 1: Generic / Shell Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 1 | General error / Operation not permitted | Check permissions, re-run command |
|
||||
| 2 | Misuse of shell builtins (syntax error) | Fix shell syntax, validate script |
|
||||
| 126 | Command invoked cannot execute | Fix file permissions (chmod +x) |
|
||||
| 127 | Command not found | Install missing package or tool |
|
||||
| 128 | Invalid argument to exit | Check exit code parameter (0-255) |
|
||||
| 130 | Terminated by Ctrl+C (SIGINT) | User interrupted - retry manually |
|
||||
| 137 | Killed (SIGKILL / Out of memory) | Insufficient RAM - increase allocation |
|
||||
| 139 | Segmentation fault (core dumped) | Serious application bug - contact support |
|
||||
| 143 | Terminated (SIGTERM) | System shutdown or manual termination |
|
||||
|
||||
### Category 2: Package Manager Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 100 | APT: Package manager error (broken packages) | Run `apt --fix-broken install` |
|
||||
| 101 | APT: Configuration error (bad sources.list) | Fix /etc/apt/sources.list, re-run apt update |
|
||||
| 255 | DPKG: Fatal internal error | Run `dpkg --configure -a` |
|
||||
|
||||
### Category 3: Node.js / npm Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 243 | Node.js: Out of memory (heap out of memory) | Increase container RAM, reduce workload |
|
||||
| 245 | Node.js: Invalid command-line option | Check node/npm arguments |
|
||||
| 246 | Node.js: Internal JavaScript Parse Error | Update Node.js version |
|
||||
| 247 | Node.js: Fatal internal error | Check Node.js installation integrity |
|
||||
| 248 | Node.js: Invalid C++ addon / N-API failure | Rebuild native modules |
|
||||
| 249 | Node.js: Inspector error | Disable debugger, retry |
|
||||
| 254 | npm/pnpm/yarn: Unknown fatal error | Check package.json, clear cache |
|
||||
|
||||
### Category 4: Python Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 210 | Python: Virtualenv / uv environment missing | Recreate virtual environment |
|
||||
| 211 | Python: Dependency resolution failed | Check package versions, fix conflicts |
|
||||
| 212 | Python: Installation aborted (EXTERNALLY-MANAGED) | Use venv or remove marker file |
|
||||
|
||||
### Category 5: Database Errors
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 231 | Connection failed (server not running) | Start PostgreSQL service |
|
||||
| 232 | Authentication failed (bad user/password) | Verify credentials |
|
||||
| 233 | Database does not exist | Create database: `createdb dbname` |
|
||||
| 234 | Fatal error in query / syntax error | Fix SQL syntax |
|
||||
|
||||
#### MySQL / MariaDB
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 241 | Connection failed (server not running) | Start MySQL/MariaDB service |
|
||||
| 242 | Authentication failed (bad user/password) | Reset password, verify credentials |
|
||||
| 243 | Database does not exist | Create database: `CREATE DATABASE dbname;` |
|
||||
| 244 | Fatal error in query / syntax error | Fix SQL syntax |
|
||||
|
||||
#### MongoDB
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 251 | Connection failed (server not running) | Start MongoDB daemon |
|
||||
| 252 | Authentication failed (bad user/password) | Verify credentials, reset if needed |
|
||||
| 253 | Database not found | Create database in MongoDB shell |
|
||||
| 254 | Fatal query error | Check query syntax |
|
||||
|
||||
### Category 6: Proxmox Custom Codes
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 200 | Failed to create lock file | Check /tmp permissions |
|
||||
| 203 | Missing CTID variable | CTID must be provided to script |
|
||||
| 204 | Missing PCT_OSTYPE variable | OS type not detected |
|
||||
| 205 | Invalid CTID (<100) | Container ID must be >= 100 |
|
||||
| 206 | CTID already in use | Check `pct list`, remove conflicting container |
|
||||
| 207 | Password contains special characters | Use alphanumeric only for passwords |
|
||||
| 208 | Invalid configuration format | Check DNS/MAC/Network format |
|
||||
| 209 | Container creation failed | Check pct create output for details |
|
||||
| 210 | Cluster not quorate | Ensure cluster nodes are online |
|
||||
| 211 | Timeout waiting for template lock | Wait for concurrent downloads to finish |
|
||||
| 214 | Not enough storage space | Free up disk space or expand storage |
|
||||
| 215 | Container created but not listed | Check /etc/pve/lxc/ for config files |
|
||||
| 216 | RootFS entry missing in config | Incomplete container creation |
|
||||
| 217 | Storage does not support rootdir | Use compatible storage backend |
|
||||
| 218 | Template corrupted or incomplete | Re-download template |
|
||||
| 220 | Unable to resolve template path | Verify template availability |
|
||||
| 221 | Template not readable | Fix file permissions |
|
||||
| 222 | Template download failed (3 attempts) | Check network/storage |
|
||||
| 223 | Template not available after download | Storage sync issue |
|
||||
| 225 | No template for OS/Version | Run `pveam available` to see options |
|
||||
| 231 | LXC stack upgrade/retry failed | Update pve-container package |
|
||||
|
||||
---
|
||||
|
||||
## Telemetry Functions
|
||||
|
||||
### `explain_exit_code()`
|
||||
|
||||
**Purpose**: Maps numeric exit codes to human-readable error descriptions. Shared between api.func and error_handler.func for consistency.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
explain_exit_code()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Numeric exit code (0-255)
|
||||
|
||||
**Returns**: Human-readable description string
|
||||
|
||||
**Supported Codes**:
|
||||
- 1-2, 126-128, 130, 137, 139, 143 (Shell)
|
||||
- 100-101, 255 (Package managers)
|
||||
- 210-212 (Python)
|
||||
- 231-234 (PostgreSQL)
|
||||
- 241-244 (MySQL/MariaDB)
|
||||
- 243-249, 254 (Node.js/npm)
|
||||
- 251-254 (MongoDB)
|
||||
- 200-231 (Proxmox custom)
|
||||
|
||||
**Default**: Returns "Unknown error" for unmapped codes
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Common error
|
||||
explain_exit_code 127
|
||||
# Output: "Command not found"
|
||||
|
||||
# Example 2: Database error
|
||||
explain_exit_code 241
|
||||
# Output: "MySQL/MariaDB: Connection failed (server not running / wrong socket)"
|
||||
|
||||
# Example 3: Custom Proxmox error
|
||||
explain_exit_code 206
|
||||
# Output: "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)"
|
||||
|
||||
# Example 4: Unknown code
|
||||
explain_exit_code 999
|
||||
# Output: "Unknown error"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `post_to_api()`
|
||||
|
||||
**Purpose**: Sends LXC container creation statistics to Community-Scripts telemetry API.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
post_to_api()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global environment variables)
|
||||
|
||||
**Returns**: No explicit return value (curl result stored in RESPONSE if diagnostics enabled)
|
||||
|
||||
**Requirements** (Silent fail if not met):
|
||||
- `curl` command available
|
||||
- `DIAGNOSTICS="yes"`
|
||||
- `RANDOM_UUID` is set
|
||||
- Executed on Proxmox host (has access to `pveversion`)
|
||||
|
||||
**Environment Variables Used**:
|
||||
- `CT_TYPE` - Container type (privileged=1, unprivileged=0)
|
||||
- `DISK_SIZE` - Allocated disk in GB
|
||||
- `CORE_COUNT` - CPU core count
|
||||
- `RAM_SIZE` - RAM allocated in MB
|
||||
- `var_os` - Operating system name
|
||||
- `var_version` - OS version
|
||||
- `NSAPP` - Normalized application name
|
||||
- `METHOD` - Installation method (default, template, etc.)
|
||||
- `DIAGNOSTICS` - Enable telemetry (yes/no)
|
||||
- `RANDOM_UUID` - Session UUID for tracking
|
||||
|
||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
|
||||
|
||||
**Payload Structure**:
|
||||
```json
|
||||
{
|
||||
"ct_type": 1, // Privileged (1) or Unprivileged (0)
|
||||
"type": "lxc", // Always "lxc" for containers
|
||||
"disk_size": 8, // GB
|
||||
"core_count": 2, // CPU cores
|
||||
"ram_size": 2048, // MB
|
||||
"os_type": "debian", // OS name
|
||||
"os_version": "12", // OS version
|
||||
"nsapp": "myapp", // Application name
|
||||
"method": "default", // Setup method
|
||||
"pve_version": "8.2.2", // Proxmox VE version
|
||||
"status": "installing", // Current status
|
||||
"random_id": "550e8400-e29b" // Session UUID (anonymous)
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Successful API post
|
||||
CT_TYPE=1
|
||||
DISK_SIZE=20
|
||||
CORE_COUNT=4
|
||||
RAM_SIZE=4096
|
||||
var_os="ubuntu"
|
||||
var_version="22.04"
|
||||
NSAPP="jellyfin"
|
||||
METHOD="default"
|
||||
DIAGNOSTICS="yes"
|
||||
RANDOM_UUID="550e8400-e29b-41d4-a716-446655440000"
|
||||
|
||||
post_to_api
|
||||
# Result: Statistics sent to API (silently, no output)
|
||||
|
||||
# Example 2: Diagnostics disabled (opt-out)
|
||||
DIAGNOSTICS="no"
|
||||
post_to_api
|
||||
# Result: Function returns immediately, no API call
|
||||
|
||||
# Example 3: Missing curl
|
||||
DIAGNOSTICS="yes"
|
||||
# curl not available in PATH
|
||||
post_to_api
|
||||
# Result: Function returns silently (curl requirement not met)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `post_to_api_vm()`
|
||||
|
||||
**Purpose**: Sends VM creation statistics to Community-Scripts API (similar to post_to_api but for virtual machines).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
post_to_api_vm()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global environment variables)
|
||||
|
||||
**Returns**: No explicit return value
|
||||
|
||||
**Requirements**: Same as `post_to_api()`
|
||||
|
||||
**Environment Variables Used**:
|
||||
- `VMID` - Virtual machine ID
|
||||
- `VM_TYPE` - VM type (kvm, etc.)
|
||||
- `VM_CORES` - CPU core count
|
||||
- `VM_RAM` - RAM in MB
|
||||
- `VM_DISK` - Disk in GB
|
||||
- `VM_OS` - Operating system
|
||||
- `VM_VERSION` - OS version
|
||||
- `VM_APP` - Application name
|
||||
- `DIAGNOSTICS` - Enable telemetry
|
||||
- `RANDOM_UUID` - Session UUID
|
||||
|
||||
**Payload Structure** (similar to containers but for VMs):
|
||||
```json
|
||||
{
|
||||
"vm_id": 100,
|
||||
"type": "qemu",
|
||||
"vm_cores": 4,
|
||||
"vm_ram": 4096,
|
||||
"vm_disk": 20,
|
||||
"vm_os": "ubuntu",
|
||||
"vm_version": "22.04",
|
||||
"vm_app": "jellyfin",
|
||||
"pve_version": "8.2.2",
|
||||
"status": "installing",
|
||||
"random_id": "550e8400-e29b"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `post_update_to_api()`
|
||||
|
||||
**Purpose**: Reports installation completion status (success/failure) for container or VM.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
post_update_to_api()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global environment variables)
|
||||
|
||||
**Returns**: No explicit return value
|
||||
|
||||
**Requirements**: Same as `post_to_api()`
|
||||
|
||||
**Environment Variables Used**:
|
||||
- `RANDOM_UUID` - Session UUID (must match initial post_to_api call)
|
||||
- `DIAGNOSTICS` - Enable telemetry
|
||||
- Installation status parameters
|
||||
|
||||
**Payload Structure**:
|
||||
```json
|
||||
{
|
||||
"status": "completed", // "completed" or "failed"
|
||||
"random_id": "550e8400-e29b", // Session UUID
|
||||
"exit_code": 0, // 0 for success, error code for failure
|
||||
"error_explanation": "" // Error description if failed
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Payload Structure
|
||||
|
||||
### Container Creation Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ct_type": 1, // 1=Privileged, 0=Unprivileged
|
||||
"type": "lxc", // Always "lxc"
|
||||
"disk_size": 20, // GB
|
||||
"core_count": 4, // CPU cores
|
||||
"ram_size": 4096, // MB
|
||||
"os_type": "debian", // Distribution name
|
||||
"os_version": "12", // Version number
|
||||
"nsapp": "jellyfin", // Application name
|
||||
"method": "default", // Setup method
|
||||
"pve_version": "8.2.2", // Proxmox VE version
|
||||
"status": "installing", // Current phase
|
||||
"random_id": "550e8400" // Unique session ID
|
||||
}
|
||||
```
|
||||
|
||||
### VM Creation Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"vm_id": 100,
|
||||
"type": "qemu",
|
||||
"vm_cores": 4,
|
||||
"vm_ram": 4096,
|
||||
"vm_disk": 20,
|
||||
"vm_os": "ubuntu",
|
||||
"vm_version": "22.04",
|
||||
"vm_app": "jellyfin",
|
||||
"pve_version": "8.2.2",
|
||||
"status": "installing",
|
||||
"random_id": "550e8400"
|
||||
}
|
||||
```
|
||||
|
||||
### Update/Completion Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "completed",
|
||||
"random_id": "550e8400",
|
||||
"exit_code": 0,
|
||||
"error_explanation": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacy & Opt-Out
|
||||
|
||||
### Privacy Policy
|
||||
|
||||
Community-Scripts telemetry is designed to be **privacy-respecting**:
|
||||
|
||||
- ✅ **Anonymous**: No personal data collected
|
||||
- ✅ **Session-based**: UUID allows correlation without identification
|
||||
- ✅ **Aggregated**: Only statistics are stored, never raw logs
|
||||
- ✅ **Opt-out capable**: Single environment variable disables all telemetry
|
||||
- ✅ **No tracking**: UUID cannot be linked to user identity
|
||||
- ✅ **No credentials**: Passwords, SSH keys never transmitted
|
||||
|
||||
### Opt-Out Methods
|
||||
|
||||
**Method 1: Environment Variable (Single Script)**
|
||||
|
||||
```bash
|
||||
DIAGNOSTICS="no" bash ct/myapp.sh
|
||||
```
|
||||
|
||||
**Method 2: Script Header (Persistent)**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
export DIAGNOSTICS="no"
|
||||
# Rest of script continues without telemetry
|
||||
```
|
||||
|
||||
**Method 3: System-wide Configuration**
|
||||
|
||||
```bash
|
||||
# In /etc/environment or ~/.bashrc
|
||||
export DIAGNOSTICS="no"
|
||||
```
|
||||
|
||||
### What Data Is Collected
|
||||
|
||||
| Data | Why | Shared? |
|
||||
|------|-----|---------|
|
||||
| Container/VM specs (cores, RAM, disk) | Understand deployment patterns | Yes, aggregated |
|
||||
| OS type/version | Track popular distributions | Yes, aggregated |
|
||||
| Application name | Understand popular apps | Yes, aggregated |
|
||||
| Method (standard vs. custom) | Measure feature usage | Yes, aggregated |
|
||||
| Success/failure status | Identify issues | Yes, aggregated |
|
||||
| Exit codes | Debug failures | Yes, anonymized |
|
||||
|
||||
### What Data Is NOT Collected
|
||||
|
||||
- ❌ Container/VM hostnames
|
||||
- ❌ IP addresses
|
||||
- ❌ User credentials
|
||||
- ❌ SSH keys or secrets
|
||||
- ❌ Application data
|
||||
- ❌ System logs
|
||||
- ❌ Any personal information
|
||||
|
||||
---
|
||||
|
||||
## Error Mapping
|
||||
|
||||
### Mapping Strategy
|
||||
|
||||
Exit codes are categorized by source:
|
||||
|
||||
```
|
||||
Exit Code Range | Source | Handling
|
||||
0 | Success | Not reported to API
|
||||
1-2 | Shell/Script | Generic error
|
||||
100-101, 255 | Package managers | APT/DPKG specific
|
||||
126-128 | Command execution | Permission/not found
|
||||
130, 143 | Signals | User interrupt/termination
|
||||
137, 139 | Kernel | OOM/segfault
|
||||
200-231 | Proxmox custom | Container creation issues
|
||||
210-212 | Python | Python environment issues
|
||||
231-234 | PostgreSQL | Database connection issues
|
||||
241-244 | MySQL/MariaDB | Database connection issues
|
||||
243-249, 254 | Node.js/npm | Runtime errors
|
||||
251-254 | MongoDB | Database connection issues
|
||||
```
|
||||
|
||||
### Custom Exit Code Usage
|
||||
|
||||
Scripts can define custom exit codes:
|
||||
|
||||
```bash
|
||||
# Example: Custom validation failure
|
||||
if [[ "$CTID" -lt 100 ]]; then
|
||||
echo "Container ID must be >= 100"
|
||||
exit 205 # Custom Proxmox code
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Always Initialize RANDOM_UUID**
|
||||
|
||||
```bash
|
||||
# Generate unique session ID for tracking
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
|
||||
# Use first 8 chars for short session ID (logs)
|
||||
SESSION_ID="${RANDOM_UUID:0:8}"
|
||||
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log"
|
||||
```
|
||||
|
||||
### 2. **Call post_to_api Early**
|
||||
|
||||
```bash
|
||||
# Call post_to_api right after container creation starts
|
||||
# This tracks attempt, even if installation fails
|
||||
|
||||
variables() {
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
# ... other variables ...
|
||||
}
|
||||
|
||||
# Later, in main script:
|
||||
post_to_api # Report container creation started
|
||||
# ... perform installation ...
|
||||
post_update_to_api # Report completion
|
||||
```
|
||||
|
||||
### 3. **Handle Graceful Failures**
|
||||
|
||||
```bash
|
||||
# Wrap API calls to handle network issues
|
||||
if command -v curl &>/dev/null; then
|
||||
post_to_api || true # Don't fail if API unavailable
|
||||
else
|
||||
msg_warn "curl not available, telemetry skipped"
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. **Respect User Opt-Out**
|
||||
|
||||
```bash
|
||||
# Check DIAGNOSTICS early and skip all API calls if disabled
|
||||
if [[ "${DIAGNOSTICS}" != "yes" ]]; then
|
||||
msg_info "Anonymous diagnostics disabled"
|
||||
return 0 # Skip telemetry
|
||||
fi
|
||||
```
|
||||
|
||||
### 5. **Maintain Session Consistency**
|
||||
|
||||
```bash
|
||||
# Use same RANDOM_UUID throughout lifecycle
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
|
||||
post_to_api # Initial report
|
||||
# ... installation ...
|
||||
post_update_to_api # Final report (same UUID links them)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Integration
|
||||
|
||||
### Connecting to API
|
||||
|
||||
The API endpoint is:
|
||||
|
||||
```
|
||||
http://api.community-scripts.org/dev/upload
|
||||
```
|
||||
|
||||
### API Response Handling
|
||||
|
||||
```bash
|
||||
# Capture HTTP response code
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
|
||||
# Extract status code (last 3 digits)
|
||||
HTTP_CODE="${RESPONSE: -3}"
|
||||
|
||||
if [[ "$HTTP_CODE" == "200" ]]; then
|
||||
msg_ok "Telemetry submitted successfully"
|
||||
elif [[ "$HTTP_CODE" == "429" ]]; then
|
||||
msg_warn "API rate limited, skipping telemetry"
|
||||
else
|
||||
msg_info "Telemetry API unreachable (this is OK)"
|
||||
fi
|
||||
```
|
||||
|
||||
### Network Resilience
|
||||
|
||||
API calls are **best-effort** and never block installation:
|
||||
|
||||
```bash
|
||||
# Telemetry should never cause container creation to fail
|
||||
if post_to_api 2>/dev/null; then
|
||||
msg_info "Diagnostics transmitted"
|
||||
fi
|
||||
# If API unavailable, continue anyway
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Exit Codes
|
||||
|
||||
1. Document in the appropriate category section
|
||||
2. Update `explain_exit_code()` in both api.func and error_handler.func
|
||||
3. Add recovery suggestions
|
||||
4. Test mapping with scripts that use the new code
|
||||
|
||||
### Testing API Integration
|
||||
|
||||
```bash
|
||||
# Test with mock curl (local testing)
|
||||
DIAGNOSTICS="yes"
|
||||
RANDOM_UUID="test-uuid-12345678"
|
||||
curl -X POST http://localhost:8000/dev/upload \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"test": "payload"}'
|
||||
|
||||
# Verify payload structure
|
||||
post_to_api 2>&1 | head -20
|
||||
```
|
||||
|
||||
### Telemetry Reporting Improvements
|
||||
|
||||
Suggestions for improvement:
|
||||
|
||||
1. Installation duration tracking
|
||||
2. Package version compatibility data
|
||||
3. Feature usage analytics
|
||||
4. Performance metrics
|
||||
5. Custom error codes
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- API calls are **silent by default** and never display sensitive information
|
||||
- Telemetry can be **completely disabled** via `DIAGNOSTICS="no"`
|
||||
- **RANDOM_UUID must be generated** before calling any post functions
|
||||
- Exit code mappings are **shared** between api.func and error_handler.func for consistency
|
||||
- API is **optional** - containers work perfectly without telemetry
|
||||
|
||||
@ -1,584 +0,0 @@
|
||||
# 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**
|
||||
|
||||
@ -1,571 +0,0 @@
|
||||
# Cloud-Init.func Wiki
|
||||
|
||||
VM cloud-init configuration and first-boot setup module for Proxmox VEs, providing automatic system initialization, network configuration, user account setup, and SSH key management for virtual machines.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Cloud-Init Fundamentals](#cloud-init-fundamentals)
|
||||
- [Main Configuration Functions](#main-configuration-functions)
|
||||
- [Interactive Configuration](#interactive-configuration)
|
||||
- [Configuration Parameters](#configuration-parameters)
|
||||
- [Data Formats](#data-formats)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Cloud-init.func provides **VM first-boot automation** infrastructure:
|
||||
|
||||
- ✅ Cloud-init drive creation (IDE2 or SCSI fallback)
|
||||
- ✅ User account and password configuration
|
||||
- ✅ SSH public key injection
|
||||
- ✅ Network configuration (DHCP or static IP)
|
||||
- ✅ DNS and search domain setup
|
||||
- ✅ Interactive whiptail-based configuration
|
||||
- ✅ Credential file generation and display
|
||||
- ✅ Support for Debian nocloud and Ubuntu cloud-init
|
||||
- ✅ System package upgrade on first boot
|
||||
|
||||
### Integration Pattern
|
||||
|
||||
```bash
|
||||
# In Proxmox VM creation scripts
|
||||
source <(curl -fsSL .../cloud-init.func)
|
||||
|
||||
# Basic setup:
|
||||
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes"
|
||||
|
||||
# Interactive setup:
|
||||
configure_cloud_init_interactive "root"
|
||||
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "$CLOUDINIT_ENABLE"
|
||||
```
|
||||
|
||||
### First-Boot Sequence
|
||||
|
||||
```
|
||||
VM Power On
|
||||
↓
|
||||
Cloud-init boot phase
|
||||
↓
|
||||
Read cloud-init config
|
||||
↓
|
||||
Create/modify user account
|
||||
↓
|
||||
Install SSH keys
|
||||
↓
|
||||
Configure network
|
||||
↓
|
||||
Set DNS/search domain
|
||||
↓
|
||||
Upgrade packages (if configured)
|
||||
↓
|
||||
Boot completion
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cloud-Init Fundamentals
|
||||
|
||||
### What is Cloud-Init?
|
||||
|
||||
Cloud-init is a system that runs on the first boot of a VM/Instance to:
|
||||
- Create user accounts
|
||||
- Set passwords
|
||||
- Configure networking
|
||||
- Install SSH keys
|
||||
- Run custom scripts
|
||||
- Manage system configuration
|
||||
|
||||
### Proxmox Cloud-Init Integration
|
||||
|
||||
Proxmox VE supports cloud-init natively via:
|
||||
- **Cloud-init drive**: IDE2 or SCSI disk with cloud-init data
|
||||
- **QEMU parameters**: User, password, SSH keys, IP configuration
|
||||
- **First-boot services**: systemd services that execute on first boot
|
||||
|
||||
### Nocloud Data Source
|
||||
|
||||
Proxmox uses the **nocloud** data source (no internet required):
|
||||
- Configuration stored on local cloud-init drive
|
||||
- No external network call needed
|
||||
- Works in isolated networks
|
||||
- Suitable for private infrastructure
|
||||
|
||||
---
|
||||
|
||||
## Main Configuration Functions
|
||||
|
||||
### `setup_cloud_init()`
|
||||
|
||||
**Purpose**: Configures Cloud-init for automatic VM first-boot setup.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
setup_cloud_init()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - VMID (required, e.g., 100)
|
||||
- `$2` - Storage name (required, e.g., local, local-lvm)
|
||||
- `$3` - Hostname (optional, default: vm-${VMID})
|
||||
- `$4` - Enable Cloud-Init (yes/no, default: no)
|
||||
- `$5` - User (optional, default: root)
|
||||
- `$6` - Network mode (dhcp/static, default: dhcp)
|
||||
- `$7` - Static IP (optional, CIDR format: 192.168.1.100/24)
|
||||
- `$8` - Gateway (optional)
|
||||
- `$9` - Nameservers (optional, space-separated, default: 1.1.1.1 8.8.8.8)
|
||||
|
||||
**Returns**: 0 on success, 1 on failure; exits if not enabled
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# If enable="no":
|
||||
# Returns immediately (skips all configuration)
|
||||
|
||||
# If enable="yes":
|
||||
# 1. Create cloud-init drive (IDE2, fallback to SCSI1)
|
||||
# 2. Set user account
|
||||
# 3. Generate random password
|
||||
# 4. Configure network
|
||||
# 5. Set DNS servers
|
||||
# 6. Add SSH keys (if available)
|
||||
# 7. Save credentials to file
|
||||
# 8. Export variables for calling script
|
||||
```
|
||||
|
||||
**Operations**:
|
||||
|
||||
| Operation | Command | Purpose |
|
||||
|-----------|---------|---------|
|
||||
| Create drive | `qm set $vmid --ide2 $storage:cloudinit` | Cloud-init data disk |
|
||||
| Set user | `qm set $vmid --ciuser $ciuser` | Initial user |
|
||||
| Set password | `qm set $vmid --cipassword $cipassword` | Auto-generated |
|
||||
| SSH keys | `qm set $vmid --sshkeys $SSH_KEYS_FILE` | Pre-injected |
|
||||
| DHCP network | `qm set $vmid --ipconfig0 ip=dhcp` | Dynamic IP |
|
||||
| Static network | `qm set $vmid --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1` | Fixed IP |
|
||||
| DNS | `qm set $vmid --nameserver $servers` | 1.1.1.1 8.8.8.8 |
|
||||
| Search domain | `qm set $vmid --searchdomain local` | Local domain |
|
||||
|
||||
**Environment Variables Set**:
|
||||
- `CLOUDINIT_USER` - Username configured
|
||||
- `CLOUDINIT_PASSWORD` - Generated password (in memory only)
|
||||
- `CLOUDINIT_CRED_FILE` - Path to credentials file
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Basic DHCP setup
|
||||
VMID=100
|
||||
STORAGE="local-lvm"
|
||||
setup_cloud_init "$VMID" "$STORAGE" "myvm" "yes"
|
||||
# Result: VM configured with DHCP, random password, root user
|
||||
|
||||
# Example 2: Static IP configuration
|
||||
setup_cloud_init "$VMID" "$STORAGE" "myvm" "yes" "root" \
|
||||
"static" "192.168.1.100/24" "192.168.1.1" "1.1.1.1 8.8.8.8"
|
||||
# Result: VM configured with static IP, specific DNS
|
||||
|
||||
# Example 3: Disabled (no cloud-init)
|
||||
setup_cloud_init "$VMID" "$STORAGE" "myvm" "no"
|
||||
# Result: Function returns immediately, no configuration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `configure_cloud_init_interactive()`
|
||||
|
||||
**Purpose**: Interactive whiptail-based configuration prompts for user preferences.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
configure_cloud_init_interactive()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Default user (optional, default: root)
|
||||
|
||||
**Returns**: 0 on success, 1 if whiptail unavailable; exports configuration variables
|
||||
|
||||
**Environment Variables Exported**:
|
||||
- `CLOUDINIT_ENABLE` - Enable (yes/no)
|
||||
- `CLOUDINIT_USER` - Username
|
||||
- `CLOUDINIT_NETWORK_MODE` - dhcp or static
|
||||
- `CLOUDINIT_IP` - Static IP (if static mode)
|
||||
- `CLOUDINIT_GW` - Gateway (if static mode)
|
||||
- `CLOUDINIT_DNS` - DNS servers (space-separated)
|
||||
|
||||
**User Prompts** (5 questions):
|
||||
1. **Enable Cloud-Init?** (yes/no)
|
||||
2. **Username?** (default: root)
|
||||
3. **Network Mode?** (DHCP or static)
|
||||
4. **Static IP?** (if static, CIDR format)
|
||||
5. **Gateway IP?** (if static)
|
||||
6. **DNS Servers?** (default: 1.1.1.1 8.8.8.8)
|
||||
|
||||
**Fallback Behavior**:
|
||||
- If whiptail unavailable: Shows warning and returns 1
|
||||
- Auto-defaults to DHCP if error occurs
|
||||
- Non-interactive: Can be skipped in scripts
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
configure_cloud_init_interactive() {
|
||||
local default_user="${1:-root}"
|
||||
|
||||
# Check whiptail availability
|
||||
if ! command -v whiptail >/dev/null 2>&1; then
|
||||
echo "Warning: whiptail not available"
|
||||
export CLOUDINIT_ENABLE="no"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Ask enable
|
||||
if ! (whiptail --backtitle "Proxmox VE Helper Scripts" --title "CLOUD-INIT" \
|
||||
--yesno "Enable Cloud-Init for VM configuration?" 16 68); then
|
||||
export CLOUDINIT_ENABLE="no"
|
||||
return 0
|
||||
fi
|
||||
|
||||
export CLOUDINIT_ENABLE="yes"
|
||||
|
||||
# Username
|
||||
CLOUDINIT_USER=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
||||
"Cloud-Init Username" 8 58 "$default_user" --title "USERNAME" 3>&1 1>&2 2>&3)
|
||||
export CLOUDINIT_USER="${CLOUDINIT_USER:-$default_user}"
|
||||
|
||||
# Network mode
|
||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "NETWORK MODE" \
|
||||
--yesno "Use DHCP for network configuration?" 10 58); then
|
||||
export CLOUDINIT_NETWORK_MODE="dhcp"
|
||||
else
|
||||
export CLOUDINIT_NETWORK_MODE="static"
|
||||
# ... prompt for static IP and gateway ...
|
||||
fi
|
||||
|
||||
# DNS servers
|
||||
CLOUDINIT_DNS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
|
||||
"DNS Servers (space-separated)" 8 58 "1.1.1.1 8.8.8.8" --title "DNS" 3>&1 1>&2 2>&3)
|
||||
export CLOUDINIT_DNS
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Interactive configuration
|
||||
configure_cloud_init_interactive "root"
|
||||
# Prompts user for all settings interactively
|
||||
# Exports variables for use in setup_cloud_init()
|
||||
|
||||
# Example 2: With custom default user
|
||||
configure_cloud_init_interactive "debian"
|
||||
# Suggests "debian" as default username
|
||||
|
||||
# Example 3: In script workflow
|
||||
configure_cloud_init_interactive "$DEFAULT_USER"
|
||||
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "$CLOUDINIT_ENABLE" "$CLOUDINIT_USER"
|
||||
# User configures interactively, then script sets up VM
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Parameters
|
||||
|
||||
### VMID (Virtual Machine ID)
|
||||
|
||||
- **Type**: Integer (100-2147483647)
|
||||
- **Required**: Yes
|
||||
- **Example**: `100`
|
||||
- **Validation**: Must be unique, >= 100 on Proxmox
|
||||
|
||||
### Storage
|
||||
|
||||
- **Type**: String (storage backend name)
|
||||
- **Required**: Yes
|
||||
- **Examples**: `local`, `local-lvm`, `ceph-rbd`
|
||||
- **Validation**: Must exist in Proxmox
|
||||
- **Cloud-init Drive**: Placed on this storage
|
||||
|
||||
### Hostname
|
||||
|
||||
- **Type**: String (valid hostname)
|
||||
- **Required**: No (defaults to vm-${VMID})
|
||||
- **Example**: `myvm`, `web-server-01`
|
||||
- **Format**: Lowercase, alphanumeric, hyphens allowed
|
||||
|
||||
### User
|
||||
|
||||
- **Type**: String (username)
|
||||
- **Required**: No (defaults: root)
|
||||
- **Example**: `root`, `ubuntu`, `debian`
|
||||
- **Cloud-init**: User account created on first boot
|
||||
|
||||
### Network Mode
|
||||
|
||||
- **Type**: Enum (dhcp, static)
|
||||
- **Default**: dhcp
|
||||
- **Options**:
|
||||
- `dhcp` - Dynamic IP from DHCP server
|
||||
- `static` - Manual IP configuration
|
||||
|
||||
### Static IP
|
||||
|
||||
- **Format**: CIDR notation (192.168.1.100/24)
|
||||
- **Example**: `192.168.1.50/24`, `10.0.0.5/8`
|
||||
- **Validation**: Valid IP and netmask
|
||||
- **Required**: If network mode = static
|
||||
|
||||
### Gateway
|
||||
|
||||
- **Format**: IP address (192.168.1.1)
|
||||
- **Example**: `192.168.1.1`, `10.0.0.1`
|
||||
- **Validation**: Valid IP
|
||||
- **Required**: If network mode = static
|
||||
|
||||
### Nameservers
|
||||
|
||||
- **Format**: Space-separated IPs
|
||||
- **Default**: `1.1.1.1 8.8.8.8`
|
||||
- **Example**: `1.1.1.1 8.8.8.8 9.9.9.9`
|
||||
|
||||
### DNS Search Domain
|
||||
|
||||
- **Type**: String
|
||||
- **Default**: `local`
|
||||
- **Example**: `example.com`, `internal.corp`
|
||||
|
||||
---
|
||||
|
||||
## Data Formats
|
||||
|
||||
### Cloud-Init Credentials File
|
||||
|
||||
Generated at: `/tmp/${hostname}-${vmid}-cloud-init-credentials.txt`
|
||||
|
||||
**Format**:
|
||||
```
|
||||
========================================
|
||||
Cloud-Init Credentials
|
||||
========================================
|
||||
VM ID: 100
|
||||
Hostname: myvm
|
||||
Created: Tue Dec 01 10:30:00 UTC 2024
|
||||
|
||||
Username: root
|
||||
Password: s7k9mL2pQ8wX
|
||||
|
||||
Network: dhcp
|
||||
DNS: 1.1.1.1 8.8.8.8
|
||||
|
||||
========================================
|
||||
SSH Access (if keys configured):
|
||||
ssh root@<vm-ip>
|
||||
|
||||
Proxmox UI Configuration:
|
||||
VM 100 > Cloud-Init > Edit
|
||||
- User, Password, SSH Keys
|
||||
- Network (IP Config)
|
||||
- DNS, Search Domain
|
||||
========================================
|
||||
```
|
||||
|
||||
### Proxmox Cloud-Init Config
|
||||
|
||||
Stored in: `/etc/pve/nodes/<node>/qemu-server/<vmid>.conf`
|
||||
|
||||
**Relevant Settings**:
|
||||
```
|
||||
ide2: local-lvm:vm-100-cloudinit,media=cdrom
|
||||
ciuser: root
|
||||
cipassword: (encrypted)
|
||||
ipconfig0: ip=dhcp
|
||||
nameserver: 1.1.1.1 8.8.8.8
|
||||
searchdomain: local
|
||||
```
|
||||
|
||||
### Network Configuration Examples
|
||||
|
||||
**DHCP**:
|
||||
```bash
|
||||
qm set 100 --ipconfig0 "ip=dhcp"
|
||||
```
|
||||
|
||||
**Static IPv4**:
|
||||
```bash
|
||||
qm set 100 --ipconfig0 "ip=192.168.1.100/24,gw=192.168.1.1"
|
||||
```
|
||||
|
||||
**Static IPv6**:
|
||||
```bash
|
||||
qm set 100 --ipconfig0 "ip6=2001:db8::100/64,gw6=2001:db8::1"
|
||||
```
|
||||
|
||||
**Dual Stack (IPv4 + IPv6)**:
|
||||
```bash
|
||||
qm set 100 --ipconfig0 "ip=192.168.1.100/24,gw=192.168.1.1,ip6=2001:db8::100/64,gw6=2001:db8::1"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Always Configure SSH Keys**
|
||||
|
||||
```bash
|
||||
# Ensure SSH keys available before cloud-init setup
|
||||
CLOUDINIT_SSH_KEYS="/root/.ssh/authorized_keys"
|
||||
|
||||
if [ ! -f "$CLOUDINIT_SSH_KEYS" ]; then
|
||||
mkdir -p /root/.ssh
|
||||
# Generate or import SSH keys
|
||||
fi
|
||||
|
||||
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes"
|
||||
```
|
||||
|
||||
### 2. **Save Credentials Securely**
|
||||
|
||||
```bash
|
||||
# After setup_cloud_init():
|
||||
# Credentials file generated at $CLOUDINIT_CRED_FILE
|
||||
|
||||
# Copy to secure location:
|
||||
cp "$CLOUDINIT_CRED_FILE" "/root/vm-credentials/"
|
||||
chmod 600 "/root/vm-credentials/$(basename $CLOUDINIT_CRED_FILE)"
|
||||
|
||||
# Or display to user:
|
||||
cat "$CLOUDINIT_CRED_FILE"
|
||||
```
|
||||
|
||||
### 3. **Use Static IPs for Production**
|
||||
|
||||
```bash
|
||||
# DHCP - suitable for dev/test
|
||||
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes" "root" "dhcp"
|
||||
|
||||
# Static - suitable for production
|
||||
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes" "root" \
|
||||
"static" "192.168.1.100/24" "192.168.1.1"
|
||||
```
|
||||
|
||||
### 4. **Validate Network Configuration**
|
||||
|
||||
```bash
|
||||
# Before setting up cloud-init, ensure:
|
||||
# - Gateway IP is reachable
|
||||
# - IP address not in use
|
||||
# - DNS servers are accessible
|
||||
|
||||
ping -c 1 "$GATEWAY" || msg_error "Gateway unreachable"
|
||||
```
|
||||
|
||||
### 5. **Test First Boot**
|
||||
|
||||
```bash
|
||||
# After cloud-init setup:
|
||||
qm start "$VMID"
|
||||
|
||||
# Wait for boot
|
||||
sleep 10
|
||||
|
||||
# Check cloud-init status
|
||||
qm exec "$VMID" cloud-init status
|
||||
|
||||
# Verify network configuration
|
||||
qm exec "$VMID" hostname -I
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Cloud-Init Not Applying
|
||||
|
||||
```bash
|
||||
# Inside VM:
|
||||
cloud-init status # Show cloud-init status
|
||||
cloud-init analyze # Analyze cloud-init boot
|
||||
cloud-init query # Query cloud-init datasource
|
||||
|
||||
# Check logs:
|
||||
tail -100 /var/log/cloud-init-output.log
|
||||
tail -100 /var/log/cloud-init.log
|
||||
```
|
||||
|
||||
### Network Not Configured
|
||||
|
||||
```bash
|
||||
# Verify cloud-init config in Proxmox:
|
||||
cat /etc/pve/nodes/$(hostname)/qemu-server/100.conf
|
||||
|
||||
# Check cloud-init drive:
|
||||
qm config 100 | grep ide2
|
||||
|
||||
# In VM, verify cloud-init wrote config:
|
||||
cat /etc/netplan/99-cloudinit.yaml
|
||||
```
|
||||
|
||||
### SSH Keys Not Installed
|
||||
|
||||
```bash
|
||||
# Verify SSH keys set in Proxmox:
|
||||
qm config 100 | grep sshkeys
|
||||
|
||||
# In VM, check SSH directory:
|
||||
ls -la /root/.ssh/
|
||||
cat /root/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
### Password Not Set
|
||||
|
||||
```bash
|
||||
# Regenerate cloud-init drive:
|
||||
qm set 100 --delete ide2 # Remove cloud-init drive
|
||||
qm set 100 --ide2 local-lvm:vm-100-cloudinit,media=cdrom # Re-create
|
||||
|
||||
# Set password again:
|
||||
qm set 100 --cipassword "newpassword"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Configuration Options
|
||||
|
||||
1. Add parameter to `setup_cloud_init()` function signature
|
||||
2. Add validation for parameter
|
||||
3. Add `qm set` command to apply configuration
|
||||
4. Update documentation with examples
|
||||
5. Test on actual Proxmox VE
|
||||
|
||||
### Enhancing Interactive Configuration
|
||||
|
||||
1. Add new whiptail dialog to `configure_cloud_init_interactive()`
|
||||
2. Export variable for use in setup
|
||||
3. Add validation logic
|
||||
4. Test with various input scenarios
|
||||
|
||||
### Supporting New Data Sources
|
||||
|
||||
Beyond nocloud, could support:
|
||||
- ConfigDrive (cloud-init standard)
|
||||
- ESXi (if supporting vSphere)
|
||||
- Hyper-V (if supporting Windows)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Cloud-init requires **QEMU guest agent** for optimal functionality
|
||||
- Network configuration applied **on first boot only**
|
||||
- Credentials file contains **sensitive information** - keep secure
|
||||
- SSH keys are **persisted** and not displayed in credentials file
|
||||
- Cloud-init is **optional** - VMs work without it
|
||||
|
||||
@ -1,918 +0,0 @@
|
||||
# Core.func Wiki
|
||||
|
||||
The foundational utility library providing colors, formatting, validation checks, message output, and execution helpers used across all Community-Scripts ecosystem projects.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Initialization Functions](#initialization-functions)
|
||||
- [Color & Formatting](#color--formatting)
|
||||
- [Validation Checks](#validation-checks)
|
||||
- [Message Output Functions](#message-output-functions)
|
||||
- [Execution Helpers](#execution-helpers)
|
||||
- [Development Mode](#development-mode)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Core.func provides essential utilities for consistent behavior across all Community-Scripts:
|
||||
|
||||
- ✅ ANSI color codes for styled terminal output
|
||||
- ✅ Standard icons and formatting for UI consistency
|
||||
- ✅ System validation checks (root, PVE version, architecture)
|
||||
- ✅ Colored message functions (info, ok, error, warn)
|
||||
- ✅ Silent command execution with log redirection
|
||||
- ✅ Spinner animations for long-running operations
|
||||
- ✅ Development mode support (trace, breakpoint, dry-run)
|
||||
- ✅ Guard clauses to prevent reloading
|
||||
|
||||
### Integration Pattern
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source <(curl -fsSL https://git.community-scripts.org/.../core.func)
|
||||
load_functions # Initialize all color/formatting/defaults
|
||||
root_check # Validate prerequisites
|
||||
pve_check # Check Proxmox VE version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Initialization Functions
|
||||
|
||||
### `load_functions()`
|
||||
|
||||
**Purpose**: Initializes all core utility function groups. Must be called once before using any core utilities.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
load_functions()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (sets global variables)
|
||||
|
||||
**Guard Mechanism**:
|
||||
```bash
|
||||
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return # Prevent re-loading
|
||||
_CORE_FUNC_LOADED=1 # Mark as loaded
|
||||
```
|
||||
|
||||
**Initializes** (in order):
|
||||
1. `color()` - ANSI color codes
|
||||
2. `formatting()` - Text formatting helpers
|
||||
3. `icons()` - Emoji/symbol constants
|
||||
4. `default_vars()` - Retry and timeout settings
|
||||
5. `set_std_mode()` - Verbose/silent mode
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Typical initialization
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions # Safe to call multiple times
|
||||
msg_info "Starting setup" # Now colors are available
|
||||
|
||||
# Example 2: Safe multiple sourcing
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions
|
||||
source <(curl -fsSL .../tools.func)
|
||||
load_functions # Silently returns (already loaded)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `color()`
|
||||
|
||||
**Purpose**: Defines ANSI escape codes for colored terminal output.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
color()
|
||||
```
|
||||
|
||||
**Color Variables Defined**:
|
||||
|
||||
| Variable | Code | Effect | Use Case |
|
||||
|----------|------|--------|----------|
|
||||
| `YW` | `\033[33m` | Yellow | Warnings, secondary info |
|
||||
| `YWB` | `\e[93m` | Bright Yellow | Emphasis, bright warnings |
|
||||
| `BL` | `\033[36m` | Cyan/Blue | Hostnames, IPs, values |
|
||||
| `RD` | `\033[01;31m` | Bright Red | Errors, critical alerts |
|
||||
| `GN` | `\033[1;92m` | Bright Green | Success, OK status |
|
||||
| `DGN` | `\033[32m` | Dark Green | Background, secondary success |
|
||||
| `BGN` | `\033[4;92m` | Green with underline | Highlights |
|
||||
| `CL` | `\033[m` | Clear | Reset to default |
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Colored output
|
||||
color
|
||||
echo -e "${RD}Error: File not found${CL}"
|
||||
# Output: "Error: File not found" (in red)
|
||||
|
||||
# Example 2: Multiple colors on one line
|
||||
echo -e "${YW}Warning:${CL} ${BL}$HOSTNAME${CL} is running low on ${RD}RAM${CL}"
|
||||
|
||||
# Example 3: In functions
|
||||
print_status() {
|
||||
echo -e "${GN}✓${CL} Operation completed"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `formatting()`
|
||||
|
||||
**Purpose**: Defines formatting helpers for terminal output.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
formatting()
|
||||
```
|
||||
|
||||
**Formatting Variables Defined**:
|
||||
|
||||
| Variable | Escape Code | Purpose |
|
||||
|----------|------------|---------|
|
||||
| `BFR` | `\r\033[K` | Backspace and clear line |
|
||||
| `BOLD` | `\033[1m` | Bold text |
|
||||
| `HOLD` | ` ` (space) | Spacing |
|
||||
| `TAB` | ` ` (2 spaces) | Indentation |
|
||||
| `TAB3` | ` ` (6 spaces) | Larger indentation |
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Overwrite previous line (progress)
|
||||
for i in {1..10}; do
|
||||
echo -en "${BFR}Progress: $i/10"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Example 2: Bold emphasis
|
||||
echo -e "${BOLD}Important:${CL} This requires attention"
|
||||
|
||||
# Example 3: Structured indentation
|
||||
echo "Main Item:"
|
||||
echo -e "${TAB}Sub-item 1"
|
||||
echo -e "${TAB}Sub-item 2"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `icons()`
|
||||
|
||||
**Purpose**: Defines symbolic emoji and icon constants used for UI consistency.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
icons()
|
||||
```
|
||||
|
||||
**Icon Variables Defined**:
|
||||
|
||||
| Variable | Icon | Use |
|
||||
|----------|------|-----|
|
||||
| `CM` | ✔️ | Success/checkmark |
|
||||
| `CROSS` | ✖️ | Error/cross |
|
||||
| `INFO` | 💡 | Information |
|
||||
| `OS` | 🖥️ | Operating system |
|
||||
| `CONTAINERTYPE` | 📦 | Container |
|
||||
| `DISKSIZE` | 💾 | Disk/storage |
|
||||
| `CPUCORE` | 🧠 | CPU |
|
||||
| `RAMSIZE` | 🛠️ | RAM |
|
||||
| `HOSTNAME` | 🏠 | Hostname |
|
||||
| `BRIDGE` | 🌉 | Network bridge |
|
||||
| `NETWORK` | 📡 | Network |
|
||||
| `GATEWAY` | 🌐 | Gateway |
|
||||
| `CREATING` | 🚀 | Creating |
|
||||
| `ADVANCED` | 🧩 | Advanced/options |
|
||||
| `HOURGLASS` | ⏳ | Wait/timer |
|
||||
|
||||
---
|
||||
|
||||
### `default_vars()`
|
||||
|
||||
**Purpose**: Sets default retry and timing variables for system operations.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
default_vars()
|
||||
```
|
||||
|
||||
**Variables Set**:
|
||||
- `RETRY_NUM=10` - Maximum retry attempts
|
||||
- `RETRY_EVERY=3` - Seconds between retries
|
||||
- `i=$RETRY_NUM` - Counter for retry loops
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Retry loop with defaults
|
||||
RETRY_NUM=10
|
||||
RETRY_EVERY=3
|
||||
i=$RETRY_NUM
|
||||
while [ $i -gt 0 ]; do
|
||||
if check_network; then
|
||||
break
|
||||
fi
|
||||
echo "Retrying... ($i attempts left)"
|
||||
sleep $RETRY_EVERY
|
||||
i=$((i - 1))
|
||||
done
|
||||
|
||||
# Example 2: Custom retry values
|
||||
RETRY_NUM=5 # Try 5 times
|
||||
RETRY_EVERY=2 # Wait 2 seconds between attempts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `set_std_mode()`
|
||||
|
||||
**Purpose**: Configures output verbosity and optional debug tracing based on environment variables.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
set_std_mode()
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- If `VERBOSE=yes`: `STD=""` (show all output)
|
||||
- If `VERBOSE=no`: `STD="silent"` (suppress output via silent() wrapper)
|
||||
- If `DEV_MODE_TRACE=true`: Enable `set -x` bash tracing
|
||||
|
||||
**Variables Set**:
|
||||
- `STD` - Command prefix for optional output suppression
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Verbose output
|
||||
VERBOSE="yes"
|
||||
set_std_mode
|
||||
$STD apt-get update # Shows all apt output
|
||||
# Output: All package manager messages displayed
|
||||
|
||||
# Example 2: Silent output
|
||||
VERBOSE="no"
|
||||
set_std_mode
|
||||
$STD apt-get update # Silently updates, logs to file
|
||||
# Output: Only progress bar or errors shown
|
||||
|
||||
# Example 3: Debug tracing
|
||||
DEV_MODE_TRACE="true"
|
||||
set_std_mode
|
||||
# bash shows every command before executing: +(script.sh:123): function_name(): cmd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `parse_dev_mode()`
|
||||
|
||||
**Purpose**: Parses comma-separated dev_mode string to enable development features.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
parse_dev_mode()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses `$dev_mode` environment variable)
|
||||
|
||||
**Supported Flags**:
|
||||
- `motd` - Setup SSH/MOTD before installation
|
||||
- `keep` - Never delete container on failure
|
||||
- `trace` - Enable bash set -x tracing
|
||||
- `pause` - Pause after each msg_info step
|
||||
- `breakpoint` - Open shell on error instead of cleanup
|
||||
- `logs` - Persist logs to /var/log/community-scripts/
|
||||
- `dryrun` - Show commands without executing
|
||||
|
||||
**Environment Variables Set**:
|
||||
- `DEV_MODE_MOTD=false|true`
|
||||
- `DEV_MODE_KEEP=false|true`
|
||||
- `DEV_MODE_TRACE=false|true`
|
||||
- `DEV_MODE_PAUSE=false|true`
|
||||
- `DEV_MODE_BREAKPOINT=false|true`
|
||||
- `DEV_MODE_LOGS=false|true`
|
||||
- `DEV_MODE_DRYRUN=false|true`
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Enable debugging
|
||||
dev_mode="trace,logs"
|
||||
parse_dev_mode
|
||||
# Enables bash tracing and persistent logging
|
||||
|
||||
# Example 2: Keep container on error
|
||||
dev_mode="keep,breakpoint"
|
||||
parse_dev_mode
|
||||
# Container never deleted on error, opens shell at breakpoint
|
||||
|
||||
# Example 3: Multiple modes
|
||||
dev_mode="motd,keep,trace,pause"
|
||||
parse_dev_mode
|
||||
# All four development modes active
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Color & Formatting
|
||||
|
||||
### Color Codes
|
||||
|
||||
**Standard Colors**:
|
||||
```bash
|
||||
${YW} # Yellow (warnings)
|
||||
${RD} # Red (errors)
|
||||
${GN} # Green (success)
|
||||
${BL} # Blue/Cyan (values)
|
||||
${CL} # Clear (reset)
|
||||
```
|
||||
|
||||
**Example Combinations**:
|
||||
```bash
|
||||
echo -e "${YW}Warning:${CL} ${RD}Critical${CL} at ${BL}$(date)${CL}"
|
||||
# Output: "Warning: Critical at 2024-12-01 10:30:00" (colored appropriately)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation Checks
|
||||
|
||||
### `shell_check()`
|
||||
|
||||
**Purpose**: Verifies script is running under Bash (not sh, dash, etc.).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
shell_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 if Bash; exits with error if not
|
||||
|
||||
**Behavior**:
|
||||
- Checks `ps -p $$ -o comm=` (current shell command)
|
||||
- Exits with error message if not "bash"
|
||||
- Clears screen for better error visibility
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions
|
||||
shell_check # Exits if run with: sh script.sh or dash script.sh
|
||||
|
||||
# If run correctly: bash script.sh - continues
|
||||
# If run with sh: Displays error and exits
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `root_check()`
|
||||
|
||||
**Purpose**: Verifies script is running with root privileges directly (not via sudo).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
root_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 if root directly; exits with error if not
|
||||
|
||||
**Checks**:
|
||||
- `id -u` must be 0 (root)
|
||||
- Parent process (`$PPID`) must not be "sudo"
|
||||
|
||||
**Why**: Some scripts require genuine root context, not sudo-elevated user shell.
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Must run as root directly, not via sudo
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions
|
||||
root_check # Will fail if: sudo bash script.sh
|
||||
|
||||
# Correct: bash script.sh (from root shell on Proxmox)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `pve_check()`
|
||||
|
||||
**Purpose**: Validates Proxmox VE version compatibility.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
pve_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 if supported version; exits with error if not
|
||||
|
||||
**Supported Versions**:
|
||||
- PVE 8.0 - 8.9
|
||||
- PVE 9.0 - 9.1
|
||||
|
||||
**Version Detection**:
|
||||
```bash
|
||||
PVE_VER=$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')
|
||||
# Example: "pveversion" → "pve-manager/8.2.2/550e8400-e29b"
|
||||
# Extracted: "8.2.2" → "8"
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: On supported PVE 8.2
|
||||
bash ct/app.sh
|
||||
# Passes: 8.2 is in range 8.0-8.9
|
||||
|
||||
# Example 2: On unsupported PVE 7.4
|
||||
bash ct/app.sh
|
||||
# Error: "This version of Proxmox VE is not supported"
|
||||
|
||||
# Example 3: On future unsupported PVE 10.0
|
||||
bash ct/app.sh
|
||||
# Error: "This version of Proxmox VE is not yet supported"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `arch_check()`
|
||||
|
||||
**Purpose**: Validates system architecture is amd64/x86_64 (not ARM/PiMox).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
arch_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 if amd64; exits with error if not
|
||||
|
||||
**Behavior**:
|
||||
- Checks `dpkg --print-architecture`
|
||||
- Exits if not "amd64"
|
||||
- Provides link to ARM64-compatible scripts
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: On x86_64 server
|
||||
arch_check
|
||||
# Passes silently
|
||||
|
||||
# Example 2: On PiMox (ARM64)
|
||||
arch_check
|
||||
# Error: "This script will not work with PiMox!"
|
||||
# Suggests: https://github.com/asylumexp/Proxmox
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `ssh_check()`
|
||||
|
||||
**Purpose**: Detects SSH connection and warns if connecting remotely (recommends Proxmox console).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
ssh_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (warning only, does not exit)
|
||||
|
||||
**Behavior**:
|
||||
- Checks `$SSH_CLIENT` environment variable
|
||||
- Analyzes client IP to determine if local or remote
|
||||
- Skips warning for local/same-subnet connections
|
||||
- Warns for external connections
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Local SSH (Proxmox WebUI console)
|
||||
ssh_check
|
||||
# No warning: Client is localhost (127.0.0.1)
|
||||
|
||||
# Example 2: External SSH over Internet
|
||||
ssh -l root 1.2.3.4 "bash script.sh"
|
||||
# Warning: "Running via external SSH (client: 1.2.3.4)"
|
||||
# Recommends Proxmox Shell (Console) instead
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Message Output Functions
|
||||
|
||||
### `msg_info()`
|
||||
|
||||
**Purpose**: Displays informational message with icon and yellow color.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
msg_info()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$@` - Message text (concatenated with spaces)
|
||||
|
||||
**Format**: `[ℹ️] Message text` (yellow)
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
msg_info "Starting container setup"
|
||||
# Output: ℹ️ Starting container setup
|
||||
|
||||
msg_info "Updating OS packages" "for debian:12"
|
||||
# Output: ℹ️ Updating OS packages for debian:12
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `msg_ok()`
|
||||
|
||||
**Purpose**: Displays success message with checkmark and green color.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
msg_ok()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$@` - Message text
|
||||
|
||||
**Format**: `[✔️] Message text` (green)
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
msg_ok "Container created"
|
||||
# Output: ✔️ Container created (in green)
|
||||
|
||||
msg_ok "Network Connected: 10.0.3.50"
|
||||
# Output: ✔️ Network Connected: 10.0.3.50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `msg_error()`
|
||||
|
||||
**Purpose**: Displays error message with cross icon and red color. Does not exit.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
msg_error()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$@` - Message text
|
||||
|
||||
**Format**: `[✖️] Message text` (red)
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
msg_error "Container ID already in use"
|
||||
# Output: ✖️ Container ID already in use (in red)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `msg_warn()`
|
||||
|
||||
**Purpose**: Displays warning message with yellow color.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
msg_warn()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$@` - Message text
|
||||
|
||||
**Format**: `[⚠️] Message text` (yellow/orange)
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
msg_warn "This will delete all data"
|
||||
# Output: ⚠️ This will delete all data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution Helpers
|
||||
|
||||
### `silent()`
|
||||
|
||||
**Purpose**: Executes command with output redirected to log file. On error: displays last 10 lines of log and exits.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
silent()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$@` - Command and arguments to execute
|
||||
|
||||
**Returns**: 0 on success; exits with original error code on failure
|
||||
|
||||
**Environment Effects**:
|
||||
- Temporarily disables `set -e` and error trap to capture exit code
|
||||
- Re-enables after command completes
|
||||
- Logs to `$BUILD_LOG` or `$INSTALL_LOG`
|
||||
|
||||
**Log Display On Error**:
|
||||
```bash
|
||||
--- Last 10 lines of silent log ---
|
||||
[log output]
|
||||
-----------------------------------
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Suppress package manager output
|
||||
silent apt-get update
|
||||
# Output: suppressed, logged to file
|
||||
|
||||
# Example 2: Conditional display on error
|
||||
silent curl -fsSL https://api.example.com
|
||||
# If curl fails: shows last 10 log lines and exits
|
||||
|
||||
# Example 3: Verbose mode shows everything
|
||||
VERBOSE="yes"
|
||||
silent apt-get update # Shows all output (STD is empty)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `spinner()`
|
||||
|
||||
**Purpose**: Displays animated spinner with rotating characters during long operations.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
spinner()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses `$SPINNER_MSG` environment variable)
|
||||
|
||||
**Animation**:
|
||||
```
|
||||
⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏ (repeating)
|
||||
```
|
||||
|
||||
**Environment Variables**:
|
||||
- `SPINNER_MSG` - Text to display with spinner
|
||||
|
||||
**Lifecycle**:
|
||||
```bash
|
||||
# Start spinner in background
|
||||
SPINNER_MSG="Downloading..."
|
||||
spinner &
|
||||
SPINNER_PID=$!
|
||||
|
||||
# ... do long operation ...
|
||||
|
||||
# Stop spinner
|
||||
stop_spinner
|
||||
|
||||
echo "Done!"
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Long operation with spinner
|
||||
SPINNER_MSG="Building container..."
|
||||
spinner &
|
||||
SPINNER_PID=$!
|
||||
|
||||
sleep 10 # Simulate work
|
||||
|
||||
stop_spinner
|
||||
msg_ok "Container created"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `clear_line()`
|
||||
|
||||
**Purpose**: Clears current terminal line and moves cursor to beginning.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
clear_line()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Implementation**: Uses `tput` or ANSI escape codes
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
for file in *.sh; do
|
||||
echo -n "Processing $file..."
|
||||
process_file "$file"
|
||||
clear_line
|
||||
done
|
||||
# Each file overwrites previous line
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `stop_spinner()`
|
||||
|
||||
**Purpose**: Stops running spinner process and cleans up temporary files.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
stop_spinner()
|
||||
```
|
||||
|
||||
**Parameters**: None (reads `$SPINNER_PID` or `/tmp/.spinner.pid`)
|
||||
|
||||
**Cleanup**:
|
||||
- Graceful kill of spinner process
|
||||
- Force kill (-9) if needed
|
||||
- Removes `/tmp/.spinner.pid` temp file
|
||||
- Resets terminal state
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Simple stop
|
||||
spinner &
|
||||
SPINNER_PID=$!
|
||||
sleep 5
|
||||
stop_spinner
|
||||
|
||||
# Example 2: In trap handler
|
||||
trap 'stop_spinner' EXIT
|
||||
spinner &
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Mode
|
||||
|
||||
### Enabling Development Features
|
||||
|
||||
**Via Environment Variable**:
|
||||
```bash
|
||||
dev_mode="trace,keep,breakpoint" bash ct/myapp.sh
|
||||
```
|
||||
|
||||
**Via Script Header**:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
export dev_mode="trace,logs,pause"
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions
|
||||
parse_dev_mode
|
||||
```
|
||||
|
||||
### Available Modes
|
||||
|
||||
| Mode | Effect |
|
||||
|------|--------|
|
||||
| `trace` | Enable bash -x tracing (verbose command logging) |
|
||||
| `keep` | Never delete container on error (for debugging) |
|
||||
| `logs` | Persist all logs to /var/log/community-scripts/ |
|
||||
| `pause` | Pause after each msg_info step (manual stepping) |
|
||||
| `breakpoint` | Open shell on error instead of immediate cleanup |
|
||||
| `motd` | Configure SSH/MOTD before installation starts |
|
||||
| `dryrun` | Show commands without executing them |
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Always Call load_functions() First**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions # MUST be before using any color variables
|
||||
|
||||
msg_info "Starting setup" # Now safe to use
|
||||
```
|
||||
|
||||
### 2. **Use Message Functions Consistently**
|
||||
|
||||
```bash
|
||||
msg_info "Starting step"
|
||||
# Do work...
|
||||
msg_ok "Step completed"
|
||||
|
||||
# Or on error:
|
||||
if ! command; then
|
||||
msg_error "Command failed"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. **Combine Validation Checks**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions
|
||||
|
||||
shell_check # Exits if wrong shell
|
||||
root_check # Exits if not root
|
||||
pve_check # Exits if unsupported version
|
||||
arch_check # Exits if wrong architecture
|
||||
|
||||
# All checks passed, safe to proceed
|
||||
msg_ok "Pre-flight checks passed"
|
||||
```
|
||||
|
||||
### 4. **Use Verbose Mode for Debugging**
|
||||
|
||||
```bash
|
||||
VERBOSE="yes" bash ct/myapp.sh
|
||||
# Shows all silent() command output for troubleshooting
|
||||
```
|
||||
|
||||
### 5. **Log Important Operations**
|
||||
|
||||
```bash
|
||||
silent apt-get update # Suppress unless error
|
||||
msg_ok "Packages updated" # Show success
|
||||
silent systemctl start nginx # Suppress unless error
|
||||
msg_ok "Nginx started" # Show success
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Message Functions
|
||||
|
||||
Follow existing pattern:
|
||||
|
||||
```bash
|
||||
msg_custom() {
|
||||
local icon="$1"
|
||||
local color="$2"
|
||||
local message="$3"
|
||||
echo -e "${TAB}${icon}${TAB}${color}${message}${CL}"
|
||||
}
|
||||
```
|
||||
|
||||
### Adding Color Support
|
||||
|
||||
New colors should follow semantic naming:
|
||||
|
||||
```bash
|
||||
BG_ERROR=$'\e[41m' # Red background for errors
|
||||
BG_SUCCESS=$'\e[42m' # Green background for success
|
||||
```
|
||||
|
||||
### Testing Color Output
|
||||
|
||||
```bash
|
||||
bash
|
||||
source <(curl -fsSL .../core.func)
|
||||
load_functions
|
||||
|
||||
echo -e "${YW}Yellow${CL} ${RD}Red${CL} ${GN}Green${CL} ${BL}Blue${CL}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Core.func is designed to be **sourced once** and **loaded everywhere**
|
||||
- All color variables are **ANSI escape codes** (work in all terminals)
|
||||
- Messages use **emoji icons** for visual consistency
|
||||
- Validation checks use **standard exit codes** (0 for success, 1 for error)
|
||||
- The module is **lightweight** and loads instantly
|
||||
|
||||
@ -279,20 +279,10 @@ echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
4. Initialize application-specific defaults
|
||||
5. Setup SSH/environment configuration
|
||||
|
||||
**Example Output**:
|
||||
```
|
||||
Setting up variables...
|
||||
Container ID: 100
|
||||
Storage: local-lvm
|
||||
Install method: Default
|
||||
```
|
||||
|
||||
#### `start()`
|
||||
|
||||
**Purpose**: Launch the container creation menu with 5 installation modes
|
||||
|
||||
**Triggered by**: Called just before `build_container()`
|
||||
|
||||
**Menu Options**:
|
||||
```
|
||||
1. Default Installation (Quick setup, predefined settings)
|
||||
@ -302,17 +292,6 @@ Install method: Default
|
||||
5. Settings Menu (Interactive mode selection)
|
||||
```
|
||||
|
||||
**User Flow**:
|
||||
```
|
||||
Select installation mode:
|
||||
1) Default
|
||||
2) Advanced
|
||||
3) User Defaults
|
||||
4) App Defaults
|
||||
5) Settings Menu
|
||||
Enter choice: 2
|
||||
```
|
||||
|
||||
#### `build_container()`
|
||||
|
||||
**Purpose**: Main orchestrator for LXC container creation
|
||||
@ -324,63 +303,19 @@ Enter choice: 2
|
||||
4. Monitors installation progress
|
||||
5. Handles errors and rollback on failure
|
||||
|
||||
**Exit Codes**:
|
||||
- `0` - Success
|
||||
- `1-255` - Various error conditions (see error_handler.func)
|
||||
|
||||
#### `description()`
|
||||
|
||||
**Purpose**: Set container description/notes visible in Proxmox UI
|
||||
|
||||
**Format**:
|
||||
```
|
||||
AppName
|
||||
IP: [IP]
|
||||
Version: [Version]
|
||||
Tags: [Tags]
|
||||
```
|
||||
|
||||
#### `header_info()`
|
||||
|
||||
**Purpose**: Display ASCII art header for application
|
||||
|
||||
**Sources**:
|
||||
- Tries `/usr/local/community-scripts/headers/ct/appname` (cached)
|
||||
- Falls back to remote fetch from GitHub
|
||||
- Returns silently if not found
|
||||
|
||||
---
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### 1. Integration with Defaults System
|
||||
|
||||
#### Save App Defaults After Installation
|
||||
|
||||
```bash
|
||||
# At end of install script, after successful setup:
|
||||
maybe_offer_save_app_defaults
|
||||
|
||||
# Output:
|
||||
# "Save these settings as App Defaults for AppName? (Y/n)"
|
||||
# Yes → Saves to /defaults/appname.vars
|
||||
# No → Skips saving
|
||||
```
|
||||
|
||||
#### Load Saved Defaults During Container Creation
|
||||
|
||||
```bash
|
||||
# In ct/AppName.sh, user selects "App Defaults" mode
|
||||
# Automatically loads /defaults/appname.vars
|
||||
# Container uses previously saved configuration
|
||||
```
|
||||
|
||||
### 2. Custom Configuration Menus
|
||||
### 1. Custom Configuration Menus
|
||||
|
||||
If your app has additional setup beyond standard vars:
|
||||
|
||||
```bash
|
||||
# In ct/AppName.sh, after variables()
|
||||
custom_app_settings() {
|
||||
CONFIGURE_DB=$(whiptail --title "Database Setup" \
|
||||
--yesno "Would you like to configure a custom database?" 8 60)
|
||||
@ -394,25 +329,11 @@ custom_app_settings() {
|
||||
custom_app_settings
|
||||
```
|
||||
|
||||
### 3. Version Tracking
|
||||
### 2. Update Function Patterns
|
||||
|
||||
Save installed version for update checks:
|
||||
Save installed version for update checks
|
||||
|
||||
```bash
|
||||
# In install script, after successful app download:
|
||||
RELEASE="1.2.3"
|
||||
echo "${RELEASE}" > /opt/${APP}_version.txt
|
||||
|
||||
# In update function, compare:
|
||||
CURRENT=$(cat /opt/${APP}_version.txt 2>/dev/null)
|
||||
LATEST=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | jq -r '.tag_name')
|
||||
|
||||
if [[ "$LATEST" != "$CURRENT" ]]; then
|
||||
echo "Update available: $CURRENT → $LATEST"
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. Health Check Functions
|
||||
### 3. Health Check Functions
|
||||
|
||||
Add custom validation:
|
||||
|
||||
@ -432,8 +353,6 @@ function health_check() {
|
||||
|
||||
msg_ok "Health check passed"
|
||||
}
|
||||
|
||||
# Called via: bash ct/appname.sh health_check
|
||||
```
|
||||
|
||||
---
|
||||
@ -461,87 +380,13 @@ color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/homarr ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
RELEASE=$(curl -fsSL https://api.github.com/repos/ajnart/homarr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}')
|
||||
|
||||
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
||||
msg_info "Updating ${APP} to v${RELEASE}"
|
||||
systemctl stop homarr
|
||||
|
||||
cd /opt/homarr
|
||||
wget -q "https://github.com/ajnart/homarr/releases/download/v${RELEASE}/docker-compose.yml"
|
||||
docker-compose up -d
|
||||
|
||||
echo "${RELEASE}" > /opt/${APP}_version.txt
|
||||
msg_ok "Updated ${APP} to v${RELEASE}"
|
||||
else
|
||||
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
||||
fi
|
||||
exit
|
||||
# Update logic here
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5100${CL}"
|
||||
```
|
||||
|
||||
### Example 2: Database App (Alpine-based)
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
||||
|
||||
APP="PostgreSQL"
|
||||
var_tags="database;sql"
|
||||
var_cpu="4"
|
||||
var_ram="4096"
|
||||
var_disk="20"
|
||||
var_os="alpine"
|
||||
var_version="3.20"
|
||||
var_unprivileged="1"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
|
||||
if ! command -v psql &>/dev/null; then
|
||||
msg_error "PostgreSQL not installed!"
|
||||
exit
|
||||
fi
|
||||
|
||||
msg_info "Updating Alpine packages"
|
||||
apk update
|
||||
apk upgrade
|
||||
msg_ok "Updated Alpine packages"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Connect using:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}psql -h ${IP} -U postgres${CL}"
|
||||
```
|
||||
|
||||
---
|
||||
@ -552,11 +397,6 @@ echo -e "${TAB}${GATEWAY}${BGN}psql -h ${IP} -U postgres${CL}"
|
||||
|
||||
**Symptom**: `pct create` exits with error code 209
|
||||
|
||||
**Causes**:
|
||||
1. CTID already exists: `pct list` shows duplicate
|
||||
2. Storage full: Check storage space
|
||||
3. Network template unavailable
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check existing containers
|
||||
@ -570,13 +410,6 @@ pct destroy CTID
|
||||
|
||||
### Update Function Doesn't Detect New Version
|
||||
|
||||
**Symptom**: Update available but script says "already at latest"
|
||||
|
||||
**Causes**:
|
||||
1. Version file missing: `/opt/AppName_version.txt`
|
||||
2. GitHub API rate limit exceeded
|
||||
3. Release tag format mismatch
|
||||
|
||||
**Debug**:
|
||||
```bash
|
||||
# Check version file
|
||||
@ -584,27 +417,6 @@ cat /opt/AppName_version.txt
|
||||
|
||||
# Test GitHub API
|
||||
curl -fsSL https://api.github.com/repos/user/repo/releases/latest | grep tag_name
|
||||
|
||||
# Inside container
|
||||
bash ct/appname.sh update_script
|
||||
```
|
||||
|
||||
### Header ASCII Art Not Displaying
|
||||
|
||||
**Symptom**: Container script runs but no header shown
|
||||
|
||||
**Causes**:
|
||||
1. Header file not in repository
|
||||
2. Caching issue
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Create header file manually
|
||||
mkdir -p /usr/local/community-scripts/headers/ct
|
||||
echo "Your ASCII art here" > /usr/local/community-scripts/headers/ct/appname
|
||||
|
||||
# Or remove cache to force re-download
|
||||
rm -f /usr/local/community-scripts/headers/ct/appname
|
||||
```
|
||||
|
||||
---
|
||||
@ -615,7 +427,7 @@ Before submitting a PR:
|
||||
|
||||
### Script Structure
|
||||
- [ ] Shebang is `#!/usr/bin/env bash`
|
||||
- [ ] Imports `build.func` from community-scripts repo (not personal fork)
|
||||
- [ ] Imports `build.func` from community-scripts repo
|
||||
- [ ] Copyright header with author and source URL
|
||||
- [ ] APP variable matches filename
|
||||
- [ ] `var_tags` are semicolon-separated (no spaces)
|
||||
@ -624,26 +436,17 @@ Before submitting a PR:
|
||||
- [ ] `var_cpu` set appropriately (2-4 for most apps)
|
||||
- [ ] `var_ram` set appropriately (1024-4096 MB minimum)
|
||||
- [ ] `var_disk` sufficient for app + data (5-20 GB)
|
||||
- [ ] `var_os` is realistic (Alpine if lightweight, Debian/Ubuntu otherwise)
|
||||
- [ ] `var_unprivileged="1"` unless app absolutely needs privileges
|
||||
- [ ] `var_os` is realistic
|
||||
|
||||
### Functions
|
||||
- [ ] `update_script()` implemented (or marked as unavailable)
|
||||
- [ ] `update_script()` implemented
|
||||
- [ ] Update function checks if app installed
|
||||
- [ ] Update function checks for new version
|
||||
- [ ] Update function performs cleanup after update
|
||||
- [ ] Proper error handling with `msg_error` on failure
|
||||
|
||||
### Output
|
||||
- [ ] Success message displayed with access URL
|
||||
- [ ] URL format: `http://IP:PORT/path` (if web-based)
|
||||
- [ ] Uses `msg_ok`, `msg_info`, `msg_error` for feedback
|
||||
- [ ] Proper error handling with `msg_error`
|
||||
|
||||
### Testing
|
||||
- [ ] Script tested with default installation
|
||||
- [ ] Script tested with advanced (19-step) installation
|
||||
- [ ] Update function tested on existing installation
|
||||
- [ ] Error handling tested (invalid settings, network issues)
|
||||
|
||||
---
|
||||
|
||||
@ -652,66 +455,18 @@ Before submitting a PR:
|
||||
### ✅ DO:
|
||||
|
||||
1. **Use meaningful defaults**
|
||||
```bash
|
||||
var_cpu="2" # ✅ Good: Typical workload
|
||||
var_cpu="128" # ❌ Bad: Unrealistic
|
||||
```
|
||||
|
||||
2. **Implement version tracking**
|
||||
```bash
|
||||
echo "${RELEASE}" > /opt/${APP}_version.txt # ✅ Good
|
||||
# ❌ Bad: No version tracking
|
||||
```
|
||||
|
||||
3. **Handle edge cases**
|
||||
```bash
|
||||
if [[ ! -f /opt/${APP}_version.txt ]]; then
|
||||
msg_info "First installation detected"
|
||||
fi
|
||||
```
|
||||
|
||||
4. **Use proper messaging**
|
||||
```bash
|
||||
msg_info "Updating..." # ✅ Good: Clear status
|
||||
echo "Updating..." # ❌ Bad: No formatting
|
||||
```
|
||||
4. **Use proper messaging with msg_info/msg_ok/msg_error**
|
||||
|
||||
### ❌ DON'T:
|
||||
|
||||
1. **Hardcode versions**
|
||||
```bash
|
||||
RELEASE="1.2.3" # ❌ Bad: Won't auto-update
|
||||
```
|
||||
|
||||
2. **Use custom color codes**
|
||||
```bash
|
||||
echo -e "\033[32mSuccess" # ❌ Bad: Use $GN instead
|
||||
```
|
||||
|
||||
2. **Use custom color codes** (use built-in variables)
|
||||
3. **Forget error handling**
|
||||
```bash
|
||||
wget file.zip # ❌ Bad: No error check
|
||||
if ! wget -q file.zip; then # ✅ Good
|
||||
msg_error "Download failed"
|
||||
fi
|
||||
```
|
||||
|
||||
4. **Leave temporary files**
|
||||
```bash
|
||||
rm -rf /opt/file.zip # ✅ Always cleanup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [install/AppName-install.sh Guide](UPDATED_APP-install.md)
|
||||
- [build.func Wiki](../misc/build.func.md)
|
||||
- [tools.func Wiki](../misc/tools.func.md)
|
||||
- [Defaults System Guide](../DEFAULTS_SYSTEM_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: December 2025
|
||||
**Compatibility**: ProxmoxVED with build.func v3+
|
||||
**Questions?** Open an issue in the repository
|
||||
@ -1,598 +0,0 @@
|
||||
# Error-Handler.func Wiki
|
||||
|
||||
Comprehensive error handling and signal management module providing exit code explanations, error handlers with logging, and signal trap configuration for all Community-Scripts projects.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Exit Code Reference](#exit-code-reference)
|
||||
- [Error Handler Functions](#error-handler-functions)
|
||||
- [Signal Traps](#signal-traps)
|
||||
- [Initialization & Setup](#initialization--setup)
|
||||
- [Error Logging](#error-logging)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Debugging](#debugging)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The error_handler.func module provides robust error handling infrastructure:
|
||||
|
||||
- ✅ Comprehensive exit code mapping (1-255+ codes documented)
|
||||
- ✅ Detailed error messages with line numbers and commands
|
||||
- ✅ Signal trap configuration (ERR, EXIT, INT, TERM, RETURN)
|
||||
- ✅ Error logging to persistent files
|
||||
- ✅ Graceful cleanup on signal termination
|
||||
- ✅ Stack trace display for debugging
|
||||
- ✅ Integration with core.func message functions
|
||||
- ✅ Container-agnostic (works in Proxmox + LXC)
|
||||
|
||||
### Error Handling Flow
|
||||
|
||||
```
|
||||
Command Execution
|
||||
↓
|
||||
ERROR (non-zero exit)
|
||||
↓
|
||||
ERR Trap Triggered
|
||||
↓
|
||||
error_handler() called
|
||||
↓
|
||||
explain_exit_code() lookup
|
||||
↓
|
||||
Display error with line/command
|
||||
↓
|
||||
Check for log file
|
||||
↓
|
||||
Exit with original code
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exit Code Reference
|
||||
|
||||
Exit codes are categorized by source system. See `api.func.md` for comprehensive mapping documentation.
|
||||
|
||||
### Quick Reference Table
|
||||
|
||||
| Range | Category | Examples |
|
||||
|-------|----------|----------|
|
||||
| 0 | Success | (no error) |
|
||||
| 1-2 | Shell errors | Syntax error, operation not permitted |
|
||||
| 100-101 | APT errors | Package manager errors |
|
||||
| 126-139 | System errors | Command not found, segfault, OOM |
|
||||
| 200-231 | Proxmox custom | Container creation errors |
|
||||
| 210-234 | Database errors | PostgreSQL, MySQL connection issues |
|
||||
| 243-254 | Runtime errors | Node.js, Python, npm errors |
|
||||
| 255 | DPKG fatal | Package system fatal error |
|
||||
|
||||
---
|
||||
|
||||
## Error Handler Functions
|
||||
|
||||
### `explain_exit_code()`
|
||||
|
||||
**Purpose**: Maps numeric exit codes to human-readable descriptions. Shared with api.func for consistency.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
explain_exit_code()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Exit code (0-255+)
|
||||
|
||||
**Returns**: Human-readable explanation string
|
||||
|
||||
**Categories Handled**:
|
||||
- Generic shell errors (1, 2, 126-128, 130, 137, 139, 143)
|
||||
- Package managers (100-101, 255)
|
||||
- Python (210-212)
|
||||
- Databases (PostgreSQL 231-234, MySQL 241-244, MongoDB 251-254)
|
||||
- Node.js/npm (243-249, 254)
|
||||
- Proxmox custom (200-231)
|
||||
- Default: "Unknown error"
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Look up error code
|
||||
explain_exit_code 127
|
||||
# Output: "Command not found"
|
||||
|
||||
# Example 2: In error logging
|
||||
error_desc=$(explain_exit_code "$exit_code")
|
||||
echo "Error: $error_desc" >> /tmp/error.log
|
||||
|
||||
# Example 3: Unknown code
|
||||
explain_exit_code 999
|
||||
# Output: "Unknown error"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `error_handler()`
|
||||
|
||||
**Purpose**: Main error handler triggered by ERR trap. Displays detailed error information and exits.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
error_handler()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` (optional) - Exit code (default: current $?)
|
||||
- `$2` (optional) - Command that failed (default: $BASH_COMMAND)
|
||||
- `$3` (optional) - Line number (default: ${BASH_LINENO[0]})
|
||||
|
||||
**Returns**: Exits with original exit code (does not return)
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
[ERROR] in line 42: exit code 1 (General error): while executing command curl https://api.example.com
|
||||
|
||||
--- Last 10 lines of log file ---
|
||||
[log content]
|
||||
------------------------------------
|
||||
```
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
error_handler() {
|
||||
local exit_code=${1:-$?}
|
||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||
local line_number=${BASH_LINENO[0]:-unknown}
|
||||
|
||||
# If successful, return silently
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get human-readable error description
|
||||
local explanation=$(explain_exit_code "$exit_code")
|
||||
|
||||
# Show cursor (might be hidden by spinner)
|
||||
printf "\e[?25h"
|
||||
|
||||
# Display error using color messages
|
||||
if declare -f msg_error >/dev/null 2>&1; then
|
||||
msg_error "in line ${line_number}: exit code ${exit_code} (${explanation}): while executing command ${command}"
|
||||
else
|
||||
echo -e "\n${RD}[ERROR]${CL} in line ${line_number}: exit code ${exit_code}: ${command}\n"
|
||||
fi
|
||||
|
||||
# Log error details if log file configured
|
||||
if [[ -n "${DEBUG_LOGFILE:-}" ]]; then
|
||||
{
|
||||
echo "------ ERROR ------"
|
||||
echo "Timestamp : $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "Exit Code : $exit_code ($explanation)"
|
||||
echo "Line : $line_number"
|
||||
echo "Command : $command"
|
||||
echo "-------------------"
|
||||
} >> "$DEBUG_LOGFILE"
|
||||
fi
|
||||
|
||||
# Show last lines of log if available
|
||||
local active_log="$(get_active_logfile)"
|
||||
if [[ -s "$active_log" ]]; then
|
||||
local log_lines=$(wc -l < "$active_log")
|
||||
echo "--- Last 10 lines of log ---"
|
||||
tail -n 10 "$active_log"
|
||||
echo "----------------------------"
|
||||
fi
|
||||
|
||||
exit "$exit_code"
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Automatic trap (recommended)
|
||||
trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR
|
||||
# Error automatically caught and handled
|
||||
|
||||
# Example 2: Manual invocation (testing)
|
||||
error_handler 1 "curl https://api.example.com" 42
|
||||
# Output: Detailed error with line number
|
||||
|
||||
# Example 3: In conditional
|
||||
if ! some_command; then
|
||||
error_handler $? "some_command" $LINENO
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Signal Traps
|
||||
|
||||
### `on_exit()`
|
||||
|
||||
**Purpose**: Cleanup handler called on normal script exit or error.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
on_exit()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: Exits with captured exit code
|
||||
|
||||
**Behavior**:
|
||||
- Captures current exit code
|
||||
- Removes lock files if present
|
||||
- Exits with original exit code
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
on_exit() {
|
||||
local exit_code="$?"
|
||||
|
||||
# Cleanup lock files
|
||||
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
|
||||
|
||||
# Preserve exit code
|
||||
exit "$exit_code"
|
||||
}
|
||||
```
|
||||
|
||||
**Trap Configuration**:
|
||||
```bash
|
||||
trap on_exit EXIT # Always called on exit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `on_interrupt()`
|
||||
|
||||
**Purpose**: Handler for Ctrl+C (SIGINT) signal. Allows graceful shutdown.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
on_interrupt()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: Exits with code 130 (standard SIGINT exit code)
|
||||
|
||||
**Output**: Displays "Interrupted by user (SIGINT)" message
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
on_interrupt() {
|
||||
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
|
||||
exit 130
|
||||
}
|
||||
```
|
||||
|
||||
**Trap Configuration**:
|
||||
```bash
|
||||
trap on_interrupt INT # Called on Ctrl+C
|
||||
```
|
||||
|
||||
**Usage Example**:
|
||||
```bash
|
||||
# Script interrupted by user:
|
||||
# Ctrl+C pressed
|
||||
# → on_interrupt() triggers
|
||||
# → "Interrupted by user (SIGINT)" displayed
|
||||
# → Exit with code 130
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `on_terminate()`
|
||||
|
||||
**Purpose**: Handler for SIGTERM signal. Allows graceful shutdown on termination.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
on_terminate()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: Exits with code 143 (standard SIGTERM exit code)
|
||||
|
||||
**Output**: Displays "Terminated by signal (SIGTERM)" message
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
on_terminate() {
|
||||
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
|
||||
exit 143
|
||||
}
|
||||
```
|
||||
|
||||
**Trap Configuration**:
|
||||
```bash
|
||||
trap on_terminate TERM # Called on SIGTERM
|
||||
```
|
||||
|
||||
**Usage Example**:
|
||||
```bash
|
||||
# System sends SIGTERM:
|
||||
# kill -TERM $PID executed
|
||||
# → on_terminate() triggers
|
||||
# → "Terminated by signal (SIGTERM)" displayed
|
||||
# → Exit with code 143
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Initialization & Setup
|
||||
|
||||
### `catch_errors()`
|
||||
|
||||
**Purpose**: Sets up all error traps and signal handlers. Called once at script start.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
catch_errors()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (configures traps)
|
||||
|
||||
**Traps Configured**:
|
||||
1. `ERR` → `error_handler()` - Catches command failures
|
||||
2. `EXIT` → `on_exit()` - Cleanup on any exit
|
||||
3. `INT` → `on_interrupt()` - Handle Ctrl+C
|
||||
4. `TERM` → `on_terminate()` - Handle SIGTERM
|
||||
5. `RETURN` → `error_handler()` - Catch function errors
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
catch_errors() {
|
||||
# Set strict mode
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Configure traps
|
||||
trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR
|
||||
trap on_exit EXIT
|
||||
trap on_interrupt INT
|
||||
trap on_terminate TERM
|
||||
trap 'error_handler $? "$BASH_COMMAND" $LINENO' RETURN
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Alpine container script
|
||||
#!/bin/sh
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
|
||||
# Now all signals handled automatically
|
||||
update_os
|
||||
|
||||
# Example 2: Proxmox host script
|
||||
#!/bin/bash
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
|
||||
# Safe to proceed with error handling
|
||||
create_container
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Logging
|
||||
|
||||
### Log File Configuration
|
||||
|
||||
**Active Log Detection**:
|
||||
```bash
|
||||
# In build.func/install.func:
|
||||
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log"
|
||||
INSTALL_LOG="/root/install-${SESSION_ID}.log"
|
||||
SILENT_LOGFILE="$(get_active_logfile)" # Points to appropriate log
|
||||
```
|
||||
|
||||
### Log Output Behavior
|
||||
|
||||
When command fails in `silent()`:
|
||||
|
||||
1. Last 10 lines of log file are displayed
|
||||
2. Full log path shown if more than 10 lines
|
||||
3. Error message includes line number where failure occurred
|
||||
4. Command that failed is displayed
|
||||
|
||||
### Accessing Error Logs
|
||||
|
||||
From Proxmox host:
|
||||
```bash
|
||||
# Host-side container creation log
|
||||
/tmp/create-lxc-<SESSION_ID>.log
|
||||
|
||||
# View error details
|
||||
tail -50 /tmp/create-lxc-550e8400.log
|
||||
grep ERROR /tmp/create-lxc-*.log
|
||||
|
||||
# Development mode persistent logs
|
||||
/var/log/community-scripts/create-lxc-<SESSION_ID>-<TIMESTAMP>.log
|
||||
```
|
||||
|
||||
From inside LXC container:
|
||||
```bash
|
||||
# Container installation log
|
||||
/root/install-<SESSION_ID>.log
|
||||
|
||||
# View recent errors
|
||||
tail -20 /root/install-550e8400.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Always Setup Traps Early**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
load_functions
|
||||
catch_errors # MUST be called before any real work
|
||||
|
||||
# Now safe - all signals handled
|
||||
```
|
||||
|
||||
### 2. **Use Meaningful Error Exit Codes**
|
||||
|
||||
```bash
|
||||
# Use Proxmox custom codes for container-specific errors
|
||||
if [[ "$CTID" -lt 100 ]]; then
|
||||
msg_error "Container ID must be >= 100"
|
||||
exit 205 # Proxmox custom code
|
||||
fi
|
||||
|
||||
# Use standard codes for common errors
|
||||
if ! command -v curl &>/dev/null; then
|
||||
msg_error "curl not installed"
|
||||
exit 127 # Command not found
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. **Log Context Information**
|
||||
|
||||
```bash
|
||||
# In error_handler, DEBUG_LOGFILE receives:
|
||||
DEBUG_LOGFILE="/tmp/debug.log"
|
||||
|
||||
# All errors logged with timestamp and details
|
||||
{
|
||||
echo "Error at $(date)"
|
||||
echo "Exit code: $exit_code"
|
||||
echo "Command: $command"
|
||||
} >> "$DEBUG_LOGFILE"
|
||||
```
|
||||
|
||||
### 4. **Graceful Signal Handling**
|
||||
|
||||
```bash
|
||||
# Setup signal handlers for cleanup
|
||||
cleanup() {
|
||||
[[ -f "$temp_file" ]] && rm -f "$temp_file"
|
||||
[[ -d "$temp_dir" ]] && rm -rf "$temp_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Now temporary files always cleaned up
|
||||
```
|
||||
|
||||
### 5. **Test Error Paths**
|
||||
|
||||
```bash
|
||||
# Force error for testing
|
||||
false # Triggers error_handler
|
||||
# or
|
||||
exit 1 # Custom error
|
||||
|
||||
# Verify error handling works correctly
|
||||
# Check log files and messages
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Stack Trace
|
||||
|
||||
```bash
|
||||
# Via environment variable
|
||||
DEV_MODE_TRACE=true bash script.sh
|
||||
|
||||
# Or in script
|
||||
set -x # Show all commands
|
||||
trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR
|
||||
```
|
||||
|
||||
### View Full Error Context
|
||||
|
||||
```bash
|
||||
# Show full log file instead of last 10 lines
|
||||
DEBUG_LOGFILE="/tmp/full-debug.log"
|
||||
|
||||
# After error, review complete context
|
||||
less /tmp/full-debug.log
|
||||
```
|
||||
|
||||
### Test Error Handler
|
||||
|
||||
```bash
|
||||
# Manually trigger error handler
|
||||
bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; exit 42'
|
||||
|
||||
# Should display:
|
||||
# [ERROR] in line N: exit code 42 (Unknown error): ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Error Codes
|
||||
|
||||
1. Assign code in appropriate range (see Exit Code Reference)
|
||||
2. Add description to `explain_exit_code()` in both:
|
||||
- error_handler.func
|
||||
- api.func (for consistency)
|
||||
3. Document in exit code table
|
||||
4. Update error mapping documentation
|
||||
|
||||
### Improving Error Messages
|
||||
|
||||
Example: Make error message more helpful:
|
||||
|
||||
```bash
|
||||
# Before:
|
||||
"Container ID must be >= 100"
|
||||
|
||||
# After:
|
||||
"Invalid CTID: $CTID. Container IDs must be >= 100. Current range: 100-999"
|
||||
```
|
||||
|
||||
### Testing Signal Handlers
|
||||
|
||||
```bash
|
||||
# Test INT signal (Ctrl+C)
|
||||
bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; sleep 30' &
|
||||
PID=$!
|
||||
sleep 1
|
||||
kill -INT $PID
|
||||
wait
|
||||
|
||||
# Test TERM signal
|
||||
bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; sleep 30' &
|
||||
PID=$!
|
||||
sleep 1
|
||||
kill -TERM $PID
|
||||
wait
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Error handler is **required** for all scripts (ensures safe cleanup)
|
||||
- Exit codes are **standardized** (0 = success, 1-255 = specific errors)
|
||||
- Signals are **trapped** to allow graceful shutdown
|
||||
- Lock files are **automatically cleaned** on exit
|
||||
- Log files contain **full error context** for debugging
|
||||
|
||||
@ -1,646 +0,0 @@
|
||||
# Install.func Wiki
|
||||
|
||||
Container installation workflow orchestration module providing network setup, OS configuration, connectivity verification, and installation mechanics for applications deployed inside LXC containers.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Initialization & Dependencies](#initialization--dependencies)
|
||||
- [Network & Connectivity Functions](#network--connectivity-functions)
|
||||
- [OS Configuration Functions](#os-configuration-functions)
|
||||
- [Installation Workflow](#installation-workflow)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Debugging](#debugging)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Install.func provides **container-internal installation mechanics**:
|
||||
|
||||
- ✅ Network connectivity verification (IPv4/IPv6)
|
||||
- ✅ OS updates and package management
|
||||
- ✅ DNS resolution validation
|
||||
- ✅ System optimization (disable wait-online service)
|
||||
- ✅ SSH and MOTD configuration
|
||||
- ✅ Container customization (auto-login, update script)
|
||||
- ✅ Comprehensive error handling with signal traps
|
||||
- ✅ Integration with core.func and error_handler.func
|
||||
|
||||
### Execution Context
|
||||
|
||||
```
|
||||
Proxmox Host LXC Container
|
||||
──────────────────────────────────────────
|
||||
pct create CTID ...
|
||||
↓
|
||||
Boot container
|
||||
↓
|
||||
pct exec CTID bash /tmp/install.sh
|
||||
↓
|
||||
[Execution within container]
|
||||
└─→ install.func functions execute
|
||||
└─→ verb_ip6()
|
||||
└─→ setting_up_container()
|
||||
└─→ network_check()
|
||||
└─→ update_os()
|
||||
└─→ etc.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Initialization & Dependencies
|
||||
|
||||
### Module Dependencies
|
||||
|
||||
```bash
|
||||
# Install.func requires two prerequisites
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
apt-get update >/dev/null 2>&1
|
||||
apt-get install -y curl >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Source core functions (colors, formatting, messages)
|
||||
source <(curl -fsSL https://git.community-scripts.org/.../core.func)
|
||||
|
||||
# Source error handling (traps, signal handlers)
|
||||
source <(curl -fsSL https://git.community-scripts.org/.../error_handler.func)
|
||||
|
||||
# Initialize both modules
|
||||
load_functions # Sets up colors, icons, defaults
|
||||
catch_errors # Configures ERR, EXIT, INT, TERM traps
|
||||
```
|
||||
|
||||
### Environment Variables Passed from Host
|
||||
|
||||
These variables are passed by build.func via `pct set` and environment:
|
||||
|
||||
| Variable | Source | Purpose |
|
||||
|----------|--------|---------|
|
||||
| `VERBOSE` | Build config | Show all output (yes/no) |
|
||||
| `PASSWORD` | User input | Root password (blank = auto-login) |
|
||||
| `DISABLEIPV6` | Advanced settings | Disable IPv6 (yes/no) |
|
||||
| `SSH_ROOT` | Advanced settings | Enable SSH root access |
|
||||
| `CACHER` | Config | Use APT cache proxy (yes/no) |
|
||||
| `CACHER_IP` | Config | APT cache IP address |
|
||||
| `APPLICATION` | App script | App display name |
|
||||
| `app` | App script | Normalized app name (lowercase) |
|
||||
| `RETRY_NUM` | core.func | Retry attempts (default: 10) |
|
||||
| `RETRY_EVERY` | core.func | Retry interval in seconds (default: 3) |
|
||||
|
||||
---
|
||||
|
||||
## Network & Connectivity Functions
|
||||
|
||||
### `verb_ip6()`
|
||||
|
||||
**Purpose**: Configures IPv6 based on DISABLEIPV6 variable and sets verbose mode.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
verb_ip6()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (configures system)
|
||||
|
||||
**Environment Requirements**:
|
||||
- `DISABLEIPV6` - Set to "yes" to disable IPv6, "no" to keep enabled
|
||||
- `VERBOSE` - Controls output verbosity via set_std_mode()
|
||||
|
||||
**Behavior**:
|
||||
```bash
|
||||
# If DISABLEIPV6=yes:
|
||||
echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
|
||||
sysctl -p # Apply immediately
|
||||
|
||||
# If DISABLEIPV6=no (default):
|
||||
# No changes (IPv6 remains enabled)
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Disable IPv6 (for security/simplicity)
|
||||
DISABLEIPV6="yes"
|
||||
VERBOSE="no"
|
||||
verb_ip6
|
||||
# Result: IPv6 disabled, change persisted
|
||||
|
||||
# Example 2: Keep IPv6 enabled (default)
|
||||
DISABLEIPV6="no"
|
||||
verb_ip6
|
||||
# Result: IPv6 operational, no configuration
|
||||
|
||||
# Example 3: Verbose mode
|
||||
VERBOSE="yes"
|
||||
verb_ip6
|
||||
# Output: Shows sysctl configuration commands
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `setting_up_container()`
|
||||
|
||||
**Purpose**: Verifies network connectivity and performs initial OS configuration for Debian/Ubuntu containers.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
setting_up_container()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 on success; exits with code 1 if network unavailable after retries
|
||||
|
||||
**Environment Requirements**:
|
||||
- `RETRY_NUM` - Max attempts (default: 10)
|
||||
- `RETRY_EVERY` - Seconds between retries (default: 3)
|
||||
|
||||
**Operations**:
|
||||
1. Verify network connectivity via `hostname -I`
|
||||
2. Retry up to RETRY_NUM times with RETRY_EVERY second delays
|
||||
3. Remove Python EXTERNALLY-MANAGED marker (allows pip)
|
||||
4. Disable systemd-networkd-wait-online.service (speeds up boot)
|
||||
5. Display network information
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
setting_up_container() {
|
||||
msg_info "Setting up Container OS"
|
||||
|
||||
# Network availability loop
|
||||
for ((i = RETRY_NUM; i > 0; i--)); do
|
||||
if [ "$(hostname -I)" != "" ]; then
|
||||
break
|
||||
fi
|
||||
echo 1>&2 -en "${CROSS}${RD} No Network! "
|
||||
sleep $RETRY_EVERY
|
||||
done
|
||||
|
||||
# Check final state
|
||||
if [ "$(hostname -I)" = "" ]; then
|
||||
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Python pip support
|
||||
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
||||
|
||||
# Speed up boot (disable wait service)
|
||||
systemctl disable -q --now systemd-networkd-wait-online.service
|
||||
|
||||
msg_ok "Set up Container OS"
|
||||
msg_ok "Network Connected: ${BL}$(hostname -I)${CL}"
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Immediate network availability
|
||||
RETRY_NUM=10
|
||||
RETRY_EVERY=3
|
||||
setting_up_container
|
||||
# Output:
|
||||
# ℹ️ Setting up Container OS
|
||||
# ✔️ Set up Container OS
|
||||
# ✔️ Network Connected: 10.0.3.50
|
||||
|
||||
# Example 2: Delayed network (waits 6 seconds)
|
||||
# Script retries 2 times before succeeding
|
||||
# (each retry waits 3 seconds)
|
||||
|
||||
# Example 3: No network
|
||||
# Script waits 30 seconds total (10 x 3)
|
||||
# Then exits with: "No Network After 10 Tries"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `network_check()`
|
||||
|
||||
**Purpose**: Comprehensive network diagnostics for both IPv4 and IPv6, including DNS validation for Git/GitHub.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
network_check()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: 0 on success; exits with code 1 on critical DNS failure
|
||||
|
||||
**Checks Performed**:
|
||||
|
||||
1. **IPv4 Connectivity** (tests 3 public DNS servers):
|
||||
- 1.1.1.1 (Cloudflare)
|
||||
- 8.8.8.8 (Google)
|
||||
- 9.9.9.9 (Quad9)
|
||||
|
||||
2. **IPv6 Connectivity** (tests 3 public DNS servers):
|
||||
- 2606:4700:4700::1111 (Cloudflare)
|
||||
- 2001:4860:4860::8888 (Google)
|
||||
- 2620:fe::fe (Quad9)
|
||||
|
||||
3. **DNS Resolution** (validates Git-related domains):
|
||||
- github.com
|
||||
- raw.githubusercontent.com
|
||||
- api.github.com
|
||||
- git.community-scripts.org
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
✔️ IPv4 Internet Connected
|
||||
✔️ IPv6 Internet Connected
|
||||
✔️ Git DNS: github.com:✔️ raw.githubusercontent.com:✔️ ...
|
||||
```
|
||||
|
||||
**Error Handling**:
|
||||
```bash
|
||||
# If both IPv4 and IPv6 fail:
|
||||
# Prompts user: "No Internet detected, would you like to continue anyway?"
|
||||
# If user says no: Exits
|
||||
# If user says yes: Shows warning "Expect Issues Without Internet"
|
||||
|
||||
# If DNS fails for GitHub:
|
||||
# Calls fatal() - exits immediately with error
|
||||
```
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
network_check() {
|
||||
set +e
|
||||
trap - ERR
|
||||
|
||||
ipv4_connected=false
|
||||
ipv6_connected=false
|
||||
|
||||
# IPv4 test
|
||||
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ...; then
|
||||
msg_ok "IPv4 Internet Connected"
|
||||
ipv4_connected=true
|
||||
else
|
||||
msg_error "IPv4 Internet Not Connected"
|
||||
fi
|
||||
|
||||
# IPv6 test
|
||||
if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ...; then
|
||||
msg_ok "IPv6 Internet Connected"
|
||||
ipv6_connected=true
|
||||
else
|
||||
msg_error "IPv6 Internet Not Connected"
|
||||
fi
|
||||
|
||||
# DNS checks for GitHub domains
|
||||
GIT_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org")
|
||||
for HOST in "${GIT_HOSTS[@]}"; do
|
||||
RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | head -n1)
|
||||
if [[ -z "$RESOLVEDIP" ]]; then
|
||||
DNS_FAILED=true
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$DNS_FAILED" == true ]]; then
|
||||
fatal "$GIT_STATUS" # Exit on critical DNS failure
|
||||
fi
|
||||
|
||||
set -e
|
||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Good connectivity (all checks pass)
|
||||
network_check
|
||||
# Output:
|
||||
# ✔️ IPv4 Internet Connected
|
||||
# ✔️ IPv6 Internet Connected
|
||||
# ✔️ Git DNS: github.com:✔️ ...
|
||||
|
||||
# Example 2: IPv6 unavailable but IPv4 OK
|
||||
network_check
|
||||
# Output:
|
||||
# ✔️ IPv4 Internet Connected
|
||||
# ✖️ IPv6 Internet Not Connected
|
||||
# ✔️ Git DNS checks OK
|
||||
|
||||
# Example 3: No internet at all
|
||||
network_check
|
||||
# Prompts: "No Internet detected, would you like to continue anyway?"
|
||||
# User: y
|
||||
# Output: ⚠️ Expect Issues Without Internet
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## OS Configuration Functions
|
||||
|
||||
### `update_os()`
|
||||
|
||||
**Purpose**: Updates Debian/Ubuntu OS packages and loads additional tools library.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
update_os()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (updates system)
|
||||
|
||||
**Operations**:
|
||||
1. Display info message
|
||||
2. Optional: Configure APT caching proxy
|
||||
3. Run `apt-get update` (index refresh)
|
||||
4. Run `apt-get dist-upgrade` (system upgrade)
|
||||
5. Remove Python EXTERNALLY-MANAGED restrictions
|
||||
6. Source tools.func for additional setup
|
||||
7. Display success message
|
||||
|
||||
**APT Caching Configuration** (if CACHER=yes):
|
||||
```bash
|
||||
# Configure apt-proxy-detect.sh
|
||||
/etc/apt/apt.conf.d/00aptproxy
|
||||
|
||||
# Script detects local APT cacher and routes through it
|
||||
# Falls back to DIRECT if unavailable
|
||||
```
|
||||
|
||||
**Implementation Pattern**:
|
||||
```bash
|
||||
update_os() {
|
||||
msg_info "Updating Container OS"
|
||||
|
||||
# Optional: Setup APT cacher
|
||||
if [[ "$CACHER" == "yes" ]]; then
|
||||
echo "Acquire::http::Proxy-Auto-Detect \"/usr/local/bin/apt-proxy-detect.sh\";" > /etc/apt/apt.conf.d/00aptproxy
|
||||
|
||||
cat > /usr/local/bin/apt-proxy-detect.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
if nc -w1 -z "${CACHER_IP}" 3142; then
|
||||
echo -n "http://${CACHER_IP}:3142"
|
||||
else
|
||||
echo -n "DIRECT"
|
||||
fi
|
||||
EOF
|
||||
chmod +x /usr/local/bin/apt-proxy-detect.sh
|
||||
fi
|
||||
|
||||
# Update system
|
||||
$STD apt-get update
|
||||
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
|
||||
|
||||
# Python support
|
||||
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
||||
|
||||
# Load additional tools library
|
||||
source <(curl -fsSL https://git.community-scripts.org/.../tools.func)
|
||||
|
||||
msg_ok "Updated Container OS"
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Standard update
|
||||
update_os
|
||||
# Output: Updates all packages silently (unless VERBOSE=yes)
|
||||
|
||||
# Example 2: With APT cacher
|
||||
CACHER="yes"
|
||||
CACHER_IP="192.168.1.100"
|
||||
update_os
|
||||
# Uses cache proxy for faster package downloads
|
||||
|
||||
# Example 3: Verbose output
|
||||
VERBOSE="yes"
|
||||
update_os
|
||||
# Shows all apt-get operations in detail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSH & MOTD Configuration
|
||||
|
||||
### `motd_ssh()`
|
||||
|
||||
**Purpose**: Configures Message of the Day and enables SSH root access if configured.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
motd_ssh()
|
||||
```
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: No explicit return value (configures system)
|
||||
|
||||
**Operations**:
|
||||
1. Set TERM environment variable for better terminal support
|
||||
2. Gather OS information (name, version, IP)
|
||||
3. Create `/etc/profile.d/00_lxc-details.sh` with container details script
|
||||
4. Optionally enable root SSH access if SSH_ROOT=yes
|
||||
|
||||
**MOTD Script Content**:
|
||||
```bash
|
||||
echo -e ""
|
||||
echo -e "${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}"
|
||||
echo -e "${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}"
|
||||
echo -e "${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}"
|
||||
echo -e "${YW} Hostname: ${GN}$(hostname)${CL}"
|
||||
echo -e "${YW} IP Address: ${GN}$(hostname -I | awk '{print $1}')${CL}"
|
||||
echo -e "${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}"
|
||||
echo ""
|
||||
```
|
||||
|
||||
**SSH Configuration** (if SSH_ROOT=yes):
|
||||
```bash
|
||||
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
|
||||
systemctl restart sshd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Installation Workflow
|
||||
|
||||
### Typical Installation Sequence
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Inside container during installation
|
||||
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
|
||||
# Step 1: Network setup
|
||||
verb_ip6
|
||||
setting_up_container
|
||||
network_check
|
||||
|
||||
# Step 2: System update
|
||||
update_os
|
||||
|
||||
# Step 3: SSH and MOTD
|
||||
motd_ssh
|
||||
|
||||
# Step 4: Install application (app-specific)
|
||||
# ... application installation steps ...
|
||||
|
||||
# Step 5: Create update script
|
||||
customize
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Always Initialize First**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
apt-get update >/dev/null 2>&1
|
||||
apt-get install -y curl >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
source <(curl -fsSL .../core.func)
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
```
|
||||
|
||||
### 2. **Check Network Early**
|
||||
|
||||
```bash
|
||||
setting_up_container # Verify network available
|
||||
network_check # Validate connectivity and DNS
|
||||
update_os # Proceed with updates
|
||||
|
||||
# If network fails, exit immediately
|
||||
# Don't waste time on installation
|
||||
```
|
||||
|
||||
### 3. **Use Retry Logic**
|
||||
|
||||
```bash
|
||||
# Built into setting_up_container():
|
||||
for ((i = RETRY_NUM; i > 0; i--)); do
|
||||
if [ "$(hostname -I)" != "" ]; then
|
||||
break
|
||||
fi
|
||||
sleep $RETRY_EVERY
|
||||
done
|
||||
|
||||
# Tolerates temporary network delay
|
||||
```
|
||||
|
||||
### 4. **Separate Concerns**
|
||||
|
||||
```bash
|
||||
# Network setup
|
||||
verb_ip6
|
||||
setting_up_container
|
||||
network_check
|
||||
|
||||
# System updates
|
||||
update_os
|
||||
|
||||
# Configuration
|
||||
motd_ssh
|
||||
|
||||
# Application-specific
|
||||
# ... app installation ...
|
||||
```
|
||||
|
||||
### 5. **Capture Environment**
|
||||
|
||||
```bash
|
||||
# Pass these from build.func:
|
||||
VERBOSE="yes" # Show all output
|
||||
DISABLEIPV6="no" # Keep IPv6
|
||||
SSH_ROOT="yes" # Enable SSH
|
||||
APPLICATION="Jellyfin" # App name
|
||||
CACHER="no" # No APT cache
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Verbose Output
|
||||
|
||||
```bash
|
||||
VERBOSE="yes" pct exec CTID bash /tmp/install.sh
|
||||
# Shows all commands and output
|
||||
```
|
||||
|
||||
### Check Network Status Inside Container
|
||||
|
||||
```bash
|
||||
pct exec CTID hostname -I
|
||||
pct exec CTID ping -c 1 1.1.1.1
|
||||
pct exec CTID getent hosts github.com
|
||||
```
|
||||
|
||||
### View Installation Log
|
||||
|
||||
```bash
|
||||
# From container
|
||||
cat /root/install-*.log
|
||||
|
||||
# Or from host (if logs mounted)
|
||||
tail -100 /var/log/community-scripts/install-*.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Network Checks
|
||||
|
||||
```bash
|
||||
network_check() {
|
||||
# ... existing checks ...
|
||||
|
||||
# Add new check:
|
||||
if ! getent hosts newhost.example.com &>/dev/null; then
|
||||
msg_warn "Unable to resolve newhost.example.com"
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### Extending OS Configuration
|
||||
|
||||
```bash
|
||||
# Add to update_os():
|
||||
update_os() {
|
||||
# ... existing updates ...
|
||||
|
||||
# Add new capability:
|
||||
$STD apt-get install -y some-package
|
||||
msg_ok "Additional package installed"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Install.func executes **inside the container** (not on Proxmox host)
|
||||
- Network connectivity is **critical** - checked early and thoroughly
|
||||
- OS updates are **required** before application installation
|
||||
- IPv6 is **configurable** but enabled by default
|
||||
- SSH and MOTD are **informational** - help with container management
|
||||
|
||||
646
docs/install/DETAILED_GUIDE.md
Normal file
646
docs/install/DETAILED_GUIDE.md
Normal file
@ -0,0 +1,646 @@
|
||||
# 🛠️ **Application Installation Scripts (install/AppName-install.sh)**
|
||||
|
||||
**Modern Guide to Writing In-Container Installation Scripts**
|
||||
|
||||
> **Updated**: December 2025
|
||||
> **Context**: Integrated with tools.func, error_handler.func, and install.func
|
||||
> **Examples Used**: `/install/pihole-install.sh`, `/install/mealie-install.sh`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Execution Context](#execution-context)
|
||||
- [File Structure](#file-structure)
|
||||
- [Complete Script Template](#complete-script-template)
|
||||
- [Installation Phases](#installation-phases)
|
||||
- [Function Reference](#function-reference)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Real Examples](#real-examples)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Contribution Checklist](#contribution-checklist)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### Purpose
|
||||
|
||||
Installation scripts (`install/AppName-install.sh`) **run inside the LXC container** and are responsible for:
|
||||
|
||||
1. Setting up the container OS (updates, packages)
|
||||
2. Installing application dependencies
|
||||
3. Downloading and configuring the application
|
||||
4. Setting up services and systemd units
|
||||
5. Creating version tracking files for updates
|
||||
6. Generating credentials/configurations
|
||||
7. Final cleanup and validation
|
||||
|
||||
### Execution Flow
|
||||
|
||||
```
|
||||
ct/AppName.sh (Proxmox Host)
|
||||
↓
|
||||
build_container()
|
||||
↓
|
||||
pct exec CTID bash -c "$(cat install/AppName-install.sh)"
|
||||
↓
|
||||
install/AppName-install.sh (Inside Container)
|
||||
↓
|
||||
Container Ready with App Installed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution Context
|
||||
|
||||
### Environment Variables Available
|
||||
|
||||
```bash
|
||||
# From Proxmox/Container
|
||||
CTID # Container ID (100, 101, etc.)
|
||||
PCT_OSTYPE # OS type (alpine, debian, ubuntu)
|
||||
HOSTNAME # Container hostname
|
||||
|
||||
# From build.func
|
||||
FUNCTIONS_FILE_PATH # Bash functions library (core.func + tools.func)
|
||||
VERBOSE # Verbose mode (yes/no)
|
||||
STD # Standard redirection variable (silent/empty)
|
||||
|
||||
# From install.func
|
||||
APP # Application name
|
||||
NSAPP # Normalized app name (lowercase, no spaces)
|
||||
METHOD # Installation method (ct/install)
|
||||
RANDOM_UUID # Session UUID for telemetry
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
### Minimal install/AppName-install.sh Template
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash # [1] Shebang
|
||||
|
||||
# [2] Copyright/Metadata
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: YourUsername
|
||||
# License: MIT
|
||||
# Source: https://example.com
|
||||
|
||||
# [3] Load functions
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
# [4] Installation steps
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt-get install -y package1 package2
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
# [5] Final setup
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Script Template
|
||||
|
||||
### Phase 1: Header & Initialization
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: YourUsername
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://github.com/application/repo
|
||||
|
||||
# Load all available functions (from core.func + tools.func)
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
|
||||
# Initialize environment
|
||||
color # Setup ANSI colors and icons
|
||||
verb_ip6 # Configure IPv6 (if needed)
|
||||
catch_errors # Setup error traps
|
||||
setting_up_container # Verify OS is ready
|
||||
network_check # Verify internet connectivity
|
||||
update_os # Update packages (apk/apt)
|
||||
```
|
||||
|
||||
### Phase 2: Dependency Installation
|
||||
|
||||
```bash
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt-get install -y \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
nano \
|
||||
build-essential \
|
||||
libssl-dev \
|
||||
python3-dev
|
||||
msg_ok "Installed Dependencies"
|
||||
```
|
||||
|
||||
### Phase 3: Tool Setup (Using tools.func)
|
||||
|
||||
```bash
|
||||
# Setup specific tool versions
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
PHP_VERSION="8.4" setup_php
|
||||
PYTHON_VERSION="3.12" setup_uv
|
||||
```
|
||||
|
||||
### Phase 4: Application Download & Setup
|
||||
|
||||
```bash
|
||||
# Download from GitHub
|
||||
RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
|
||||
grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
|
||||
|
||||
wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app-${RELEASE}.tar.gz"
|
||||
cd /opt
|
||||
tar -xzf app-${RELEASE}.tar.gz
|
||||
rm -f app-${RELEASE}.tar.gz
|
||||
```
|
||||
|
||||
### Phase 5: Configuration Files
|
||||
|
||||
```bash
|
||||
# Using cat << EOF (multiline)
|
||||
cat <<'EOF' >/etc/nginx/sites-available/appname
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /opt/appname/public;
|
||||
index index.php index.html;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Using sed for replacements
|
||||
sed -i -e "s|^DB_HOST=.*|DB_HOST=localhost|" \
|
||||
-e "s|^DB_USER=.*|DB_USER=appuser|" \
|
||||
/opt/appname/.env
|
||||
```
|
||||
|
||||
### Phase 6: Database Setup (If Needed)
|
||||
|
||||
```bash
|
||||
msg_info "Setting up Database"
|
||||
|
||||
DB_NAME="appname_db"
|
||||
DB_USER="appuser"
|
||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
||||
|
||||
# For MySQL/MariaDB
|
||||
mysql -u root <<EOF
|
||||
CREATE DATABASE ${DB_NAME};
|
||||
CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
||||
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EOF
|
||||
|
||||
msg_ok "Database setup complete"
|
||||
```
|
||||
|
||||
### Phase 7: Permission & Ownership
|
||||
|
||||
```bash
|
||||
msg_info "Setting permissions"
|
||||
|
||||
# Web applications typically run as www-data
|
||||
chown -R www-data:www-data /opt/appname
|
||||
chmod -R 755 /opt/appname
|
||||
chmod -R 644 /opt/appname/*
|
||||
chmod 755 /opt/appname/*/.*
|
||||
|
||||
msg_ok "Permissions set"
|
||||
```
|
||||
|
||||
### Phase 8: Service Configuration
|
||||
|
||||
```bash
|
||||
# Enable systemd service
|
||||
systemctl enable -q --now appname
|
||||
|
||||
# Or for OpenRC (Alpine)
|
||||
rc-service appname start
|
||||
rc-update add appname default
|
||||
|
||||
# Verify service is running
|
||||
if systemctl is-active --quiet appname; then
|
||||
msg_ok "Service running successfully"
|
||||
else
|
||||
msg_error "Service failed to start"
|
||||
journalctl -u appname -n 20
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Phase 9: Version Tracking
|
||||
|
||||
```bash
|
||||
# Essential for update detection
|
||||
echo "${RELEASE}" > /opt/${APP}_version.txt
|
||||
|
||||
# Or with additional metadata
|
||||
cat > /opt/${APP}_version.txt <<EOF
|
||||
Version: ${RELEASE}
|
||||
InstallDate: $(date)
|
||||
InstallMethod: ${METHOD}
|
||||
EOF
|
||||
```
|
||||
|
||||
### Phase 10: Final Setup & Cleanup
|
||||
|
||||
```bash
|
||||
# Display MOTD and enable autologin
|
||||
motd_ssh
|
||||
|
||||
# Final customization
|
||||
customize
|
||||
|
||||
# Clean up package manager cache
|
||||
msg_info "Cleaning up"
|
||||
apt-get -y autoremove
|
||||
apt-get -y autoclean
|
||||
msg_ok "Cleaned"
|
||||
|
||||
# Or for Alpine
|
||||
apk cache clean
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# System cleanup
|
||||
cleanup_lxc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Installation Phases
|
||||
|
||||
### Phase 1: Container OS Setup
|
||||
- Network interface brought up and configured
|
||||
- Internet connectivity verified
|
||||
- Package lists updated
|
||||
- All OS packages upgraded to latest versions
|
||||
|
||||
### Phase 2: Base Dependencies
|
||||
```bash
|
||||
msg_info "Installing Base Dependencies"
|
||||
$STD apt-get install -y \
|
||||
curl wget git nano build-essential
|
||||
msg_ok "Installed Base Dependencies"
|
||||
```
|
||||
|
||||
### Phase 3: Tool Installation
|
||||
```bash
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
PHP_VERSION="8.4" setup_php
|
||||
```
|
||||
|
||||
### Phase 4: Application Setup
|
||||
```bash
|
||||
RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
|
||||
grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
|
||||
wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app.tar.gz"
|
||||
```
|
||||
|
||||
### Phase 5: Configuration
|
||||
Application-specific configuration files and environment setup
|
||||
|
||||
### Phase 6: Service Registration
|
||||
Enable and verify systemd services are running
|
||||
|
||||
---
|
||||
|
||||
## Function Reference
|
||||
|
||||
### Core Messaging Functions
|
||||
|
||||
#### `msg_info(message)`
|
||||
|
||||
Displays an info message with spinner animation
|
||||
|
||||
```bash
|
||||
msg_info "Installing application"
|
||||
# Output: ⏳ Installing application (with spinning animation)
|
||||
```
|
||||
|
||||
#### `msg_ok(message)`
|
||||
|
||||
Displays success message with checkmark
|
||||
|
||||
```bash
|
||||
msg_ok "Installation completed"
|
||||
# Output: ✔️ Installation completed
|
||||
```
|
||||
|
||||
#### `msg_error(message)`
|
||||
|
||||
Displays error message and exits
|
||||
|
||||
```bash
|
||||
msg_error "Installation failed"
|
||||
# Output: ✖️ Installation failed
|
||||
```
|
||||
|
||||
### Package Management
|
||||
|
||||
#### `$STD` Variable
|
||||
|
||||
Controls output verbosity
|
||||
|
||||
```bash
|
||||
# Silent mode (respects VERBOSE setting)
|
||||
$STD apt-get install -y nginx
|
||||
```
|
||||
|
||||
#### `update_os()`
|
||||
|
||||
Updates OS packages
|
||||
|
||||
```bash
|
||||
update_os
|
||||
# Runs: apt update && apt upgrade
|
||||
```
|
||||
|
||||
### Tool Installation Functions
|
||||
|
||||
#### `setup_nodejs()`
|
||||
|
||||
Installs Node.js with optional global modules
|
||||
|
||||
```bash
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
NODE_VERSION="22" NODE_MODULE="yarn,@vue/cli" setup_nodejs
|
||||
```
|
||||
|
||||
#### `setup_php()`
|
||||
|
||||
Installs PHP with optional extensions
|
||||
|
||||
```bash
|
||||
PHP_VERSION="8.4" PHP_MODULE="bcmath,curl,gd,intl,redis" setup_php
|
||||
```
|
||||
|
||||
#### Other Tools
|
||||
|
||||
```bash
|
||||
setup_mariadb # MariaDB database
|
||||
setup_mysql # MySQL database
|
||||
setup_postgresql # PostgreSQL
|
||||
setup_docker # Docker Engine
|
||||
setup_composer # PHP Composer
|
||||
setup_python # Python 3
|
||||
setup_ruby # Ruby
|
||||
setup_rust # Rust
|
||||
```
|
||||
|
||||
### Cleanup Functions
|
||||
|
||||
#### `cleanup_lxc()`
|
||||
|
||||
Comprehensive container cleanup
|
||||
|
||||
- Removes package manager caches
|
||||
- Cleans temporary files
|
||||
- Clears language package caches
|
||||
- Removes systemd journal logs
|
||||
|
||||
```bash
|
||||
cleanup_lxc
|
||||
# Output: ⏳ Cleaning up
|
||||
# ✔️ Cleaned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### ✅ DO:
|
||||
|
||||
1. **Always Use $STD for Commands**
|
||||
```bash
|
||||
# ✅ Good: Respects VERBOSE setting
|
||||
$STD apt-get install -y nginx
|
||||
```
|
||||
|
||||
2. **Generate Random Passwords Safely**
|
||||
```bash
|
||||
# ✅ Good: Alphanumeric only
|
||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
||||
```
|
||||
|
||||
3. **Check Command Success**
|
||||
```bash
|
||||
# ✅ Good: Verify success
|
||||
if ! wget -q "https://example.com/file.tar.gz"; then
|
||||
msg_error "Download failed"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
4. **Set Proper Permissions**
|
||||
```bash
|
||||
# ✅ Good: Explicit permissions
|
||||
chown -R www-data:www-data /opt/appname
|
||||
chmod -R 755 /opt/appname
|
||||
```
|
||||
|
||||
5. **Save Version for Update Checks**
|
||||
```bash
|
||||
# ✅ Good: Version tracked
|
||||
echo "${RELEASE}" > /opt/${APP}_version.txt
|
||||
```
|
||||
|
||||
6. **Handle Alpine vs Debian Differences**
|
||||
```bash
|
||||
# ✅ Good: Detect OS
|
||||
if grep -qi 'alpine' /etc/os-release; then
|
||||
apk add package
|
||||
else
|
||||
apt-get install -y package
|
||||
fi
|
||||
```
|
||||
|
||||
### ❌ DON'T:
|
||||
|
||||
1. **Hardcode Versions**
|
||||
```bash
|
||||
# ❌ Bad: Won't auto-update
|
||||
wget https://example.com/app-1.2.3.tar.gz
|
||||
```
|
||||
|
||||
2. **Use Root Without Password**
|
||||
```bash
|
||||
# ❌ Bad: Security risk
|
||||
mysql -u root
|
||||
```
|
||||
|
||||
3. **Forget Error Handling**
|
||||
```bash
|
||||
# ❌ Bad: Silent failures
|
||||
wget https://example.com/file
|
||||
tar -xzf file
|
||||
```
|
||||
|
||||
4. **Leave Temporary Files**
|
||||
```bash
|
||||
# ✅ Always cleanup
|
||||
rm -rf /opt/app-${RELEASE}.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Real Examples
|
||||
|
||||
### Example 1: Node.js Application
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
|
||||
color
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing Node.js"
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
msg_ok "Node.js installed"
|
||||
|
||||
msg_info "Installing Application"
|
||||
cd /opt
|
||||
RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
|
||||
grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
|
||||
wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app.tar.gz"
|
||||
tar -xzf app.tar.gz
|
||||
echo "${RELEASE}" > /opt/app_version.txt
|
||||
msg_ok "Application installed"
|
||||
|
||||
systemctl enable --now app
|
||||
cleanup_lxc
|
||||
```
|
||||
|
||||
### Example 2: PHP Application with Database
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
|
||||
color
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
PHP_VERSION="8.4" PHP_MODULE="bcmath,curl,pdo_mysql" setup_php
|
||||
MARIADB_VERSION="11.4" setup_mariadb
|
||||
|
||||
# Database setup
|
||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
||||
mysql -u root <<EOF
|
||||
CREATE DATABASE appdb;
|
||||
CREATE USER 'appuser'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
||||
GRANT ALL ON appdb.* TO 'appuser'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EOF
|
||||
|
||||
# App installation
|
||||
cd /opt
|
||||
wget -q https://github.com/user/repo/releases/latest/download/app.tar.gz
|
||||
tar -xzf app.tar.gz
|
||||
|
||||
# Configuration
|
||||
cat > /opt/app/.env <<EOF
|
||||
DB_HOST=localhost
|
||||
DB_NAME=appdb
|
||||
DB_USER=appuser
|
||||
DB_PASS=${DB_PASS}
|
||||
EOF
|
||||
|
||||
chown -R www-data:www-data /opt/app
|
||||
systemctl enable --now php-fpm
|
||||
cleanup_lxc
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Installation Hangs
|
||||
|
||||
**Check internet connectivity**:
|
||||
```bash
|
||||
ping -c 1 8.8.8.8
|
||||
```
|
||||
|
||||
**Enable verbose mode**:
|
||||
```bash
|
||||
# In ct/AppName.sh, before running
|
||||
VERBOSE="yes" bash install/AppName-install.sh
|
||||
```
|
||||
|
||||
### Package Not Found
|
||||
|
||||
**Update package lists**:
|
||||
```bash
|
||||
apt update
|
||||
apt-cache search package_name
|
||||
```
|
||||
|
||||
### Service Won't Start
|
||||
|
||||
**Check logs**:
|
||||
```bash
|
||||
journalctl -u appname -n 50
|
||||
systemctl status appname
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contribution Checklist
|
||||
|
||||
Before submitting a PR:
|
||||
|
||||
### Structure
|
||||
- [ ] Shebang is `#!/usr/bin/env bash`
|
||||
- [ ] Loads functions from `$FUNCTIONS_FILE_PATH`
|
||||
- [ ] Copyright header with author
|
||||
- [ ] Clear phase comments
|
||||
|
||||
### Installation
|
||||
- [ ] `setting_up_container` called early
|
||||
- [ ] `network_check` before downloads
|
||||
- [ ] `update_os` before package installation
|
||||
- [ ] All errors checked properly
|
||||
|
||||
### Functions
|
||||
- [ ] Uses `msg_info/msg_ok/msg_error` for status
|
||||
- [ ] Uses `$STD` for command output silencing
|
||||
- [ ] Version saved to `/opt/${APP}_version.txt`
|
||||
- [ ] Proper permissions set
|
||||
|
||||
### Cleanup
|
||||
- [ ] `motd_ssh` called for final setup
|
||||
- [ ] `customize` called for options
|
||||
- [ ] `cleanup_lxc` called at end
|
||||
|
||||
### Testing
|
||||
- [ ] Tested with default settings
|
||||
- [ ] Tested with advanced (19-step) mode
|
||||
- [ ] Service starts and runs correctly
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: December 2025
|
||||
**Compatibility**: ProxmoxVED with install.func v3+
|
||||
@ -1,670 +0,0 @@
|
||||
# API.func Wiki
|
||||
|
||||
A telemetry and diagnostics module providing anonymous statistics collection and API integration with the Community-Scripts infrastructure for tracking container/VM creation metrics and installation success/failure data.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Exit Code Reference](#exit-code-reference)
|
||||
- [Telemetry Functions](#telemetry-functions)
|
||||
- [API Payload Structure](#api-payload-structure)
|
||||
- [Privacy & Opt-Out](#privacy--opt-out)
|
||||
- [Error Mapping](#error-mapping)
|
||||
- [Best Practices](#best-practices)
|
||||
- [API Integration](#api-integration)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The API.func module provides anonymous telemetry reporting to Community-Scripts infrastructure, enabling:
|
||||
|
||||
- ✅ Container/VM creation statistics collection
|
||||
- ✅ Installation success/failure tracking
|
||||
- ✅ Comprehensive exit code mapping and explanation
|
||||
- ✅ Anonymous session-based tracking (UUID)
|
||||
- ✅ Privacy-respecting data collection (no personal data)
|
||||
- ✅ Opt-out capability via DIAGNOSTICS setting
|
||||
- ✅ Consistent error reporting across all scripts
|
||||
|
||||
### Integration Points
|
||||
|
||||
```bash
|
||||
# In container build scripts (on Proxmox host):
|
||||
source <(curl -fsSL .../api.func)
|
||||
post_to_api # Report container creation
|
||||
post_update_to_api # Report installation completion
|
||||
|
||||
# Error handling (in all scripts):
|
||||
source <(curl -fsSL .../error_handler.func)
|
||||
# explain_exit_code shared for consistent mappings
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
Container/VM Creation
|
||||
↓
|
||||
post_to_api()
|
||||
↓
|
||||
Community-Scripts API
|
||||
↓
|
||||
Anonymous Statistics
|
||||
(No personal data)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exit Code Reference
|
||||
|
||||
### Category 1: Generic / Shell Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 1 | General error / Operation not permitted | Check permissions, re-run command |
|
||||
| 2 | Misuse of shell builtins (syntax error) | Fix shell syntax, validate script |
|
||||
| 126 | Command invoked cannot execute | Fix file permissions (chmod +x) |
|
||||
| 127 | Command not found | Install missing package or tool |
|
||||
| 128 | Invalid argument to exit | Check exit code parameter (0-255) |
|
||||
| 130 | Terminated by Ctrl+C (SIGINT) | User interrupted - retry manually |
|
||||
| 137 | Killed (SIGKILL / Out of memory) | Insufficient RAM - increase allocation |
|
||||
| 139 | Segmentation fault (core dumped) | Serious application bug - contact support |
|
||||
| 143 | Terminated (SIGTERM) | System shutdown or manual termination |
|
||||
|
||||
### Category 2: Package Manager Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 100 | APT: Package manager error (broken packages) | Run `apt --fix-broken install` |
|
||||
| 101 | APT: Configuration error (bad sources.list) | Fix /etc/apt/sources.list, re-run apt update |
|
||||
| 255 | DPKG: Fatal internal error | Run `dpkg --configure -a` |
|
||||
|
||||
### Category 3: Node.js / npm Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 243 | Node.js: Out of memory (heap out of memory) | Increase container RAM, reduce workload |
|
||||
| 245 | Node.js: Invalid command-line option | Check node/npm arguments |
|
||||
| 246 | Node.js: Internal JavaScript Parse Error | Update Node.js version |
|
||||
| 247 | Node.js: Fatal internal error | Check Node.js installation integrity |
|
||||
| 248 | Node.js: Invalid C++ addon / N-API failure | Rebuild native modules |
|
||||
| 249 | Node.js: Inspector error | Disable debugger, retry |
|
||||
| 254 | npm/pnpm/yarn: Unknown fatal error | Check package.json, clear cache |
|
||||
|
||||
### Category 4: Python Errors
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 210 | Python: Virtualenv / uv environment missing | Recreate virtual environment |
|
||||
| 211 | Python: Dependency resolution failed | Check package versions, fix conflicts |
|
||||
| 212 | Python: Installation aborted (EXTERNALLY-MANAGED) | Use venv or remove marker file |
|
||||
|
||||
### Category 5: Database Errors
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 231 | Connection failed (server not running) | Start PostgreSQL service |
|
||||
| 232 | Authentication failed (bad user/password) | Verify credentials |
|
||||
| 233 | Database does not exist | Create database: `createdb dbname` |
|
||||
| 234 | Fatal error in query / syntax error | Fix SQL syntax |
|
||||
|
||||
#### MySQL / MariaDB
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 241 | Connection failed (server not running) | Start MySQL/MariaDB service |
|
||||
| 242 | Authentication failed (bad user/password) | Reset password, verify credentials |
|
||||
| 243 | Database does not exist | Create database: `CREATE DATABASE dbname;` |
|
||||
| 244 | Fatal error in query / syntax error | Fix SQL syntax |
|
||||
|
||||
#### MongoDB
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 251 | Connection failed (server not running) | Start MongoDB daemon |
|
||||
| 252 | Authentication failed (bad user/password) | Verify credentials, reset if needed |
|
||||
| 253 | Database not found | Create database in MongoDB shell |
|
||||
| 254 | Fatal query error | Check query syntax |
|
||||
|
||||
### Category 6: Proxmox Custom Codes
|
||||
|
||||
| Code | Meaning | Recovery |
|
||||
|------|---------|----------|
|
||||
| 200 | Failed to create lock file | Check /tmp permissions |
|
||||
| 203 | Missing CTID variable | CTID must be provided to script |
|
||||
| 204 | Missing PCT_OSTYPE variable | OS type not detected |
|
||||
| 205 | Invalid CTID (<100) | Container ID must be >= 100 |
|
||||
| 206 | CTID already in use | Check `pct list`, remove conflicting container |
|
||||
| 207 | Password contains special characters | Use alphanumeric only for passwords |
|
||||
| 208 | Invalid configuration format | Check DNS/MAC/Network format |
|
||||
| 209 | Container creation failed | Check pct create output for details |
|
||||
| 210 | Cluster not quorate | Ensure cluster nodes are online |
|
||||
| 211 | Timeout waiting for template lock | Wait for concurrent downloads to finish |
|
||||
| 214 | Not enough storage space | Free up disk space or expand storage |
|
||||
| 215 | Container created but not listed | Check /etc/pve/lxc/ for config files |
|
||||
| 216 | RootFS entry missing in config | Incomplete container creation |
|
||||
| 217 | Storage does not support rootdir | Use compatible storage backend |
|
||||
| 218 | Template corrupted or incomplete | Re-download template |
|
||||
| 220 | Unable to resolve template path | Verify template availability |
|
||||
| 221 | Template not readable | Fix file permissions |
|
||||
| 222 | Template download failed (3 attempts) | Check network/storage |
|
||||
| 223 | Template not available after download | Storage sync issue |
|
||||
| 225 | No template for OS/Version | Run `pveam available` to see options |
|
||||
| 231 | LXC stack upgrade/retry failed | Update pve-container package |
|
||||
|
||||
---
|
||||
|
||||
## Telemetry Functions
|
||||
|
||||
### `explain_exit_code()`
|
||||
|
||||
**Purpose**: Maps numeric exit codes to human-readable error descriptions. Shared between api.func and error_handler.func for consistency.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
explain_exit_code()
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `$1` - Numeric exit code (0-255)
|
||||
|
||||
**Returns**: Human-readable description string
|
||||
|
||||
**Supported Codes**:
|
||||
- 1-2, 126-128, 130, 137, 139, 143 (Shell)
|
||||
- 100-101, 255 (Package managers)
|
||||
- 210-212 (Python)
|
||||
- 231-234 (PostgreSQL)
|
||||
- 241-244 (MySQL/MariaDB)
|
||||
- 243-249, 254 (Node.js/npm)
|
||||
- 251-254 (MongoDB)
|
||||
- 200-231 (Proxmox custom)
|
||||
|
||||
**Default**: Returns "Unknown error" for unmapped codes
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Common error
|
||||
explain_exit_code 127
|
||||
# Output: "Command not found"
|
||||
|
||||
# Example 2: Database error
|
||||
explain_exit_code 241
|
||||
# Output: "MySQL/MariaDB: Connection failed (server not running / wrong socket)"
|
||||
|
||||
# Example 3: Custom Proxmox error
|
||||
explain_exit_code 206
|
||||
# Output: "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)"
|
||||
|
||||
# Example 4: Unknown code
|
||||
explain_exit_code 999
|
||||
# Output: "Unknown error"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `post_to_api()`
|
||||
|
||||
**Purpose**: Sends LXC container creation statistics to Community-Scripts telemetry API.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
post_to_api()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global environment variables)
|
||||
|
||||
**Returns**: No explicit return value (curl result stored in RESPONSE if diagnostics enabled)
|
||||
|
||||
**Requirements** (Silent fail if not met):
|
||||
- `curl` command available
|
||||
- `DIAGNOSTICS="yes"`
|
||||
- `RANDOM_UUID` is set
|
||||
- Executed on Proxmox host (has access to `pveversion`)
|
||||
|
||||
**Environment Variables Used**:
|
||||
- `CT_TYPE` - Container type (privileged=1, unprivileged=0)
|
||||
- `DISK_SIZE` - Allocated disk in GB
|
||||
- `CORE_COUNT` - CPU core count
|
||||
- `RAM_SIZE` - RAM allocated in MB
|
||||
- `var_os` - Operating system name
|
||||
- `var_version` - OS version
|
||||
- `NSAPP` - Normalized application name
|
||||
- `METHOD` - Installation method (default, template, etc.)
|
||||
- `DIAGNOSTICS` - Enable telemetry (yes/no)
|
||||
- `RANDOM_UUID` - Session UUID for tracking
|
||||
|
||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
|
||||
|
||||
**Payload Structure**:
|
||||
```json
|
||||
{
|
||||
"ct_type": 1, // Privileged (1) or Unprivileged (0)
|
||||
"type": "lxc", // Always "lxc" for containers
|
||||
"disk_size": 8, // GB
|
||||
"core_count": 2, // CPU cores
|
||||
"ram_size": 2048, // MB
|
||||
"os_type": "debian", // OS name
|
||||
"os_version": "12", // OS version
|
||||
"nsapp": "myapp", // Application name
|
||||
"method": "default", // Setup method
|
||||
"pve_version": "8.2.2", // Proxmox VE version
|
||||
"status": "installing", // Current status
|
||||
"random_id": "550e8400-e29b" // Session UUID (anonymous)
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples**:
|
||||
|
||||
```bash
|
||||
# Example 1: Successful API post
|
||||
CT_TYPE=1
|
||||
DISK_SIZE=20
|
||||
CORE_COUNT=4
|
||||
RAM_SIZE=4096
|
||||
var_os="ubuntu"
|
||||
var_version="22.04"
|
||||
NSAPP="jellyfin"
|
||||
METHOD="default"
|
||||
DIAGNOSTICS="yes"
|
||||
RANDOM_UUID="550e8400-e29b-41d4-a716-446655440000"
|
||||
|
||||
post_to_api
|
||||
# Result: Statistics sent to API (silently, no output)
|
||||
|
||||
# Example 2: Diagnostics disabled (opt-out)
|
||||
DIAGNOSTICS="no"
|
||||
post_to_api
|
||||
# Result: Function returns immediately, no API call
|
||||
|
||||
# Example 3: Missing curl
|
||||
DIAGNOSTICS="yes"
|
||||
# curl not available in PATH
|
||||
post_to_api
|
||||
# Result: Function returns silently (curl requirement not met)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `post_to_api_vm()`
|
||||
|
||||
**Purpose**: Sends VM creation statistics to Community-Scripts API (similar to post_to_api but for virtual machines).
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
post_to_api_vm()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global environment variables)
|
||||
|
||||
**Returns**: No explicit return value
|
||||
|
||||
**Requirements**: Same as `post_to_api()`
|
||||
|
||||
**Environment Variables Used**:
|
||||
- `VMID` - Virtual machine ID
|
||||
- `VM_TYPE` - VM type (kvm, etc.)
|
||||
- `VM_CORES` - CPU core count
|
||||
- `VM_RAM` - RAM in MB
|
||||
- `VM_DISK` - Disk in GB
|
||||
- `VM_OS` - Operating system
|
||||
- `VM_VERSION` - OS version
|
||||
- `VM_APP` - Application name
|
||||
- `DIAGNOSTICS` - Enable telemetry
|
||||
- `RANDOM_UUID` - Session UUID
|
||||
|
||||
**Payload Structure** (similar to containers but for VMs):
|
||||
```json
|
||||
{
|
||||
"vm_id": 100,
|
||||
"type": "qemu",
|
||||
"vm_cores": 4,
|
||||
"vm_ram": 4096,
|
||||
"vm_disk": 20,
|
||||
"vm_os": "ubuntu",
|
||||
"vm_version": "22.04",
|
||||
"vm_app": "jellyfin",
|
||||
"pve_version": "8.2.2",
|
||||
"status": "installing",
|
||||
"random_id": "550e8400-e29b"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `post_update_to_api()`
|
||||
|
||||
**Purpose**: Reports installation completion status (success/failure) for container or VM.
|
||||
|
||||
**Signature**:
|
||||
```bash
|
||||
post_update_to_api()
|
||||
```
|
||||
|
||||
**Parameters**: None (uses global environment variables)
|
||||
|
||||
**Returns**: No explicit return value
|
||||
|
||||
**Requirements**: Same as `post_to_api()`
|
||||
|
||||
**Environment Variables Used**:
|
||||
- `RANDOM_UUID` - Session UUID (must match initial post_to_api call)
|
||||
- `DIAGNOSTICS` - Enable telemetry
|
||||
- Installation status parameters
|
||||
|
||||
**Payload Structure**:
|
||||
```json
|
||||
{
|
||||
"status": "completed", // "completed" or "failed"
|
||||
"random_id": "550e8400-e29b", // Session UUID
|
||||
"exit_code": 0, // 0 for success, error code for failure
|
||||
"error_explanation": "" // Error description if failed
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Payload Structure
|
||||
|
||||
### Container Creation Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ct_type": 1, // 1=Privileged, 0=Unprivileged
|
||||
"type": "lxc", // Always "lxc"
|
||||
"disk_size": 20, // GB
|
||||
"core_count": 4, // CPU cores
|
||||
"ram_size": 4096, // MB
|
||||
"os_type": "debian", // Distribution name
|
||||
"os_version": "12", // Version number
|
||||
"nsapp": "jellyfin", // Application name
|
||||
"method": "default", // Setup method
|
||||
"pve_version": "8.2.2", // Proxmox VE version
|
||||
"status": "installing", // Current phase
|
||||
"random_id": "550e8400" // Unique session ID
|
||||
}
|
||||
```
|
||||
|
||||
### VM Creation Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"vm_id": 100,
|
||||
"type": "qemu",
|
||||
"vm_cores": 4,
|
||||
"vm_ram": 4096,
|
||||
"vm_disk": 20,
|
||||
"vm_os": "ubuntu",
|
||||
"vm_version": "22.04",
|
||||
"vm_app": "jellyfin",
|
||||
"pve_version": "8.2.2",
|
||||
"status": "installing",
|
||||
"random_id": "550e8400"
|
||||
}
|
||||
```
|
||||
|
||||
### Update/Completion Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "completed",
|
||||
"random_id": "550e8400",
|
||||
"exit_code": 0,
|
||||
"error_explanation": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacy & Opt-Out
|
||||
|
||||
### Privacy Policy
|
||||
|
||||
Community-Scripts telemetry is designed to be **privacy-respecting**:
|
||||
|
||||
- ✅ **Anonymous**: No personal data collected
|
||||
- ✅ **Session-based**: UUID allows correlation without identification
|
||||
- ✅ **Aggregated**: Only statistics are stored, never raw logs
|
||||
- ✅ **Opt-out capable**: Single environment variable disables all telemetry
|
||||
- ✅ **No tracking**: UUID cannot be linked to user identity
|
||||
- ✅ **No credentials**: Passwords, SSH keys never transmitted
|
||||
|
||||
### Opt-Out Methods
|
||||
|
||||
**Method 1: Environment Variable (Single Script)**
|
||||
|
||||
```bash
|
||||
DIAGNOSTICS="no" bash ct/myapp.sh
|
||||
```
|
||||
|
||||
**Method 2: Script Header (Persistent)**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
export DIAGNOSTICS="no"
|
||||
# Rest of script continues without telemetry
|
||||
```
|
||||
|
||||
**Method 3: System-wide Configuration**
|
||||
|
||||
```bash
|
||||
# In /etc/environment or ~/.bashrc
|
||||
export DIAGNOSTICS="no"
|
||||
```
|
||||
|
||||
### What Data Is Collected
|
||||
|
||||
| Data | Why | Shared? |
|
||||
|------|-----|---------|
|
||||
| Container/VM specs (cores, RAM, disk) | Understand deployment patterns | Yes, aggregated |
|
||||
| OS type/version | Track popular distributions | Yes, aggregated |
|
||||
| Application name | Understand popular apps | Yes, aggregated |
|
||||
| Method (standard vs. custom) | Measure feature usage | Yes, aggregated |
|
||||
| Success/failure status | Identify issues | Yes, aggregated |
|
||||
| Exit codes | Debug failures | Yes, anonymized |
|
||||
|
||||
### What Data Is NOT Collected
|
||||
|
||||
- ❌ Container/VM hostnames
|
||||
- ❌ IP addresses
|
||||
- ❌ User credentials
|
||||
- ❌ SSH keys or secrets
|
||||
- ❌ Application data
|
||||
- ❌ System logs
|
||||
- ❌ Any personal information
|
||||
|
||||
---
|
||||
|
||||
## Error Mapping
|
||||
|
||||
### Mapping Strategy
|
||||
|
||||
Exit codes are categorized by source:
|
||||
|
||||
```
|
||||
Exit Code Range | Source | Handling
|
||||
0 | Success | Not reported to API
|
||||
1-2 | Shell/Script | Generic error
|
||||
100-101, 255 | Package managers | APT/DPKG specific
|
||||
126-128 | Command execution | Permission/not found
|
||||
130, 143 | Signals | User interrupt/termination
|
||||
137, 139 | Kernel | OOM/segfault
|
||||
200-231 | Proxmox custom | Container creation issues
|
||||
210-212 | Python | Python environment issues
|
||||
231-234 | PostgreSQL | Database connection issues
|
||||
241-244 | MySQL/MariaDB | Database connection issues
|
||||
243-249, 254 | Node.js/npm | Runtime errors
|
||||
251-254 | MongoDB | Database connection issues
|
||||
```
|
||||
|
||||
### Custom Exit Code Usage
|
||||
|
||||
Scripts can define custom exit codes:
|
||||
|
||||
```bash
|
||||
# Example: Custom validation failure
|
||||
if [[ "$CTID" -lt 100 ]]; then
|
||||
echo "Container ID must be >= 100"
|
||||
exit 205 # Custom Proxmox code
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. **Always Initialize RANDOM_UUID**
|
||||
|
||||
```bash
|
||||
# Generate unique session ID for tracking
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
|
||||
# Use first 8 chars for short session ID (logs)
|
||||
SESSION_ID="${RANDOM_UUID:0:8}"
|
||||
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log"
|
||||
```
|
||||
|
||||
### 2. **Call post_to_api Early**
|
||||
|
||||
```bash
|
||||
# Call post_to_api right after container creation starts
|
||||
# This tracks attempt, even if installation fails
|
||||
|
||||
variables() {
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
# ... other variables ...
|
||||
}
|
||||
|
||||
# Later, in main script:
|
||||
post_to_api # Report container creation started
|
||||
# ... perform installation ...
|
||||
post_update_to_api # Report completion
|
||||
```
|
||||
|
||||
### 3. **Handle Graceful Failures**
|
||||
|
||||
```bash
|
||||
# Wrap API calls to handle network issues
|
||||
if command -v curl &>/dev/null; then
|
||||
post_to_api || true # Don't fail if API unavailable
|
||||
else
|
||||
msg_warn "curl not available, telemetry skipped"
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. **Respect User Opt-Out**
|
||||
|
||||
```bash
|
||||
# Check DIAGNOSTICS early and skip all API calls if disabled
|
||||
if [[ "${DIAGNOSTICS}" != "yes" ]]; then
|
||||
msg_info "Anonymous diagnostics disabled"
|
||||
return 0 # Skip telemetry
|
||||
fi
|
||||
```
|
||||
|
||||
### 5. **Maintain Session Consistency**
|
||||
|
||||
```bash
|
||||
# Use same RANDOM_UUID throughout lifecycle
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
|
||||
post_to_api # Initial report
|
||||
# ... installation ...
|
||||
post_update_to_api # Final report (same UUID links them)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Integration
|
||||
|
||||
### Connecting to API
|
||||
|
||||
The API endpoint is:
|
||||
|
||||
```
|
||||
http://api.community-scripts.org/dev/upload
|
||||
```
|
||||
|
||||
### API Response Handling
|
||||
|
||||
```bash
|
||||
# Capture HTTP response code
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
|
||||
# Extract status code (last 3 digits)
|
||||
HTTP_CODE="${RESPONSE: -3}"
|
||||
|
||||
if [[ "$HTTP_CODE" == "200" ]]; then
|
||||
msg_ok "Telemetry submitted successfully"
|
||||
elif [[ "$HTTP_CODE" == "429" ]]; then
|
||||
msg_warn "API rate limited, skipping telemetry"
|
||||
else
|
||||
msg_info "Telemetry API unreachable (this is OK)"
|
||||
fi
|
||||
```
|
||||
|
||||
### Network Resilience
|
||||
|
||||
API calls are **best-effort** and never block installation:
|
||||
|
||||
```bash
|
||||
# Telemetry should never cause container creation to fail
|
||||
if post_to_api 2>/dev/null; then
|
||||
msg_info "Diagnostics transmitted"
|
||||
fi
|
||||
# If API unavailable, continue anyway
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
### Adding New Exit Codes
|
||||
|
||||
1. Document in the appropriate category section
|
||||
2. Update `explain_exit_code()` in both api.func and error_handler.func
|
||||
3. Add recovery suggestions
|
||||
4. Test mapping with scripts that use the new code
|
||||
|
||||
### Testing API Integration
|
||||
|
||||
```bash
|
||||
# Test with mock curl (local testing)
|
||||
DIAGNOSTICS="yes"
|
||||
RANDOM_UUID="test-uuid-12345678"
|
||||
curl -X POST http://localhost:8000/dev/upload \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"test": "payload"}'
|
||||
|
||||
# Verify payload structure
|
||||
post_to_api 2>&1 | head -20
|
||||
```
|
||||
|
||||
### Telemetry Reporting Improvements
|
||||
|
||||
Suggestions for improvement:
|
||||
|
||||
1. Installation duration tracking
|
||||
2. Package version compatibility data
|
||||
3. Feature usage analytics
|
||||
4. Performance metrics
|
||||
5. Custom error codes
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- API calls are **silent by default** and never display sensitive information
|
||||
- Telemetry can be **completely disabled** via `DIAGNOSTICS="no"`
|
||||
- **RANDOM_UUID must be generated** before calling any post functions
|
||||
- Exit code mappings are **shared** between api.func and error_handler.func for consistency
|
||||
- API is **optional** - containers work perfectly without telemetry
|
||||
|
||||
1283
docs/tools.func.md
1283
docs/tools.func.md
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user