Files
Pulse/scripts/lib/README.md
rcourtman 0fcfad3dc5 feat: add shared script library system and refactor docker-agent installer
Implements a comprehensive script improvement infrastructure to reduce code
duplication, improve maintainability, and enable easier testing of installer
scripts.

## New Infrastructure

### Shared Library System (scripts/lib/)
- common.sh: Core utilities (logging, sudo, dry-run, cleanup management)
- systemd.sh: Service management helpers with container-safe systemctl
- http.sh: HTTP/download helpers with curl/wget fallback and retry logic
- README.md: Complete API documentation for all library functions

### Bundler System
- scripts/bundle.sh: Concatenates library modules into single-file installers
- scripts/bundle.manifest: Defines bundling configuration for distributables
- Enables both modular development and curl|bash distribution

### Test Infrastructure
- scripts/tests/run.sh: Test harness for running all smoke tests
- scripts/tests/test-common-lib.sh: Common library validation (5 tests)
- scripts/tests/test-docker-agent-v2.sh: Installer smoke tests (4 tests)
- scripts/tests/integration/: Container-based integration tests (5 scenarios)
- All tests passing ✓

## Refactored Installer

### install-docker-agent-v2.sh
- Reduced from 1098 to 563 lines (48% code reduction)
- Uses shared libraries for all common operations
- NEW: --dry-run flag support
- Maintains 100% backward compatibility with original
- Fully tested with smoke and integration tests

### Key Improvements
- Sudo escalation: 100+ lines → 1 function call
- Download logic: 51 lines → 1 function call
- Service creation: 33 lines → 2 function calls
- Logging: Standardized across all operations
- Error handling: Improved with common library

## Documentation

### Rollout Strategy (docs/installer-v2-rollout.md)
- 3-phase rollout plan (Alpha → Beta → GA)
- Feature flag mechanism for gradual deployment
- Testing checklist and success metrics
- Rollback procedures and communication plan

### Developer Guides
- docs/script-library-guide.md: Complete library usage guide
- docs/CONTRIBUTING-SCRIPTS.md: Contribution workflow
- docs/installer-v2-quickref.md: Quick reference for operators

## Metrics

- Code reduction: 48% (1098 → 563 lines)
- Reusable functions: 0 → 30+
- Test coverage: 0 → 8 test scenarios
- Documentation: 0 → 5 comprehensive guides

## Testing

All tests passing:
- Smoke tests: 2/2 passed (8 test cases)
- Integration tests: 5/5 scenarios passed
- Bundled output: Syntax validated, dry-run tested

## Next Steps

This lays the foundation for migrating other installers (install.sh,
install-sensor-proxy.sh) to use the same pattern, reducing overall
maintenance burden and improving code quality across the project.
2025-10-20 15:13:38 +00:00

85 lines
5.0 KiB
Markdown

# Pulse Script Library
The `scripts/lib` directory houses shared Bash modules used by Pulse installation and maintenance scripts. The goal is to keep production installers modular and testable while still supporting bundled single-file artifacts for curl-based distribution.
## Modules & Namespaces
- Each module lives in `scripts/lib/<module>.sh`.
- Public functions use the `module::function` namespace (`common::log_info`, `proxmox::get_nodes`, etc.).
- Internal helpers can be marked `local` or use a `module::__helper` prefix.
- Scripts should only rely on documented `module::` APIs.
## Using the Library
### Development Mode
```bash
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/lib" && pwd)"
if [[ -f "${LIB_DIR}/common.sh" ]]; then
# shellcheck disable=SC1090
source "${LIB_DIR}/common.sh"
fi
common::init "$@"
common::log_info "Starting installer..."
# Acquire a temp directory (automatically cleaned on exit)
common::temp_dir TMP_DIR --prefix pulse-install-
common::log_info "Working in ${TMP_DIR}"
```
### Bundled Mode
Bundled scripts have the library concatenated into the file during the release process. The `source` guard remains but is a no-op because all functions are already defined.
## Environment Variables
| Variable | Description |
|----------------------|------------------------------------------------------------------------------|
| `PULSE_DEBUG` | When set to `1`, forces debug logging and enables additional diagnostics. |
| `PULSE_LOG_LEVEL` | Sets log level (`debug`, `info`, `warn`, `error`). Defaults to `info`. |
| `PULSE_NO_COLOR` | When `1`, disables ANSI colors (used for non-TTY or forced monochrome). |
| `PULSE_SUDO_CMD` | Overrides the sudo command (e.g., `/usr/bin/doas`). |
| `PULSE_FORCE_INTERACTIVE` | Forces interactive behavior (treats script as running in a TTY). |
## `common.sh` API Reference
- `common::init "$@"` — Initializes logging, traps, and script metadata. Call once at script start.
- `common::log_info "msg"` — Logs informational messages to stdout.
- `common::log_warn "msg"` — Logs warnings to stderr.
- `common::log_error "msg"` — Logs errors to stderr.
- `common::log_debug "msg"` — Logs debug output (requires log level `debug`).
- `common::fail "msg" [--code N]` — Logs error and exits with optional status code.
- `common::require_command cmd...` — Verifies required commands exist; exits on missing dependencies.
- `common::is_interactive` — Returns success when stdin/stdout are TTYs or forced interactive.
- `common::ensure_root [--allow-sudo] [--args "${COMMON__ORIGINAL_ARGS[@]}"]` — Ensures root privileges, optionally re-executing via sudo.
- `common::sudo_exec command...` — Executes command with sudo, printing guidance if sudo is unavailable.
- `common::run [--label desc] [--retries N] [--backoff "1 2"] -- cmd...` — Executes a command with optional retries and dry-run support.
- `common::run_capture [--label desc] -- cmd...` — Runs a command and prints captured stdout; honors dry-run.
- `common::temp_dir VAR [--prefix name]` — Creates a temporary directory, assigns it to `VAR`, and registers cleanup (avoid command substitution so handlers persist).
- `common::cleanup_push "description" "command"` — Registers cleanup/rollback handler (LIFO order).
- `common::cleanup_run` — Executes registered cleanup handlers; automatically called on exit.
- `common::set_dry_run true|false` — Enables or disables dry-run mode for command wrappers.
- `common::is_dry_run` — Returns success when dry-run mode is active.
## Bundling Workflow
1. Define modules under `scripts/lib/`.
2. Reference them from scripts using the development source guard.
3. Update `scripts/bundle.manifest` to list output artifacts and module order.
4. Run `scripts/bundle.sh` to generate bundled files under `dist/`.
5. Distribute bundled files (e.g., replace production installer).
Headers inserted during bundling (`# === Begin: ... ===`) mark module boundaries and aid debugging. The generated file includes provenance metadata with timestamp and manifest path.
- `systemd.sh` — safe wrappers around `systemctl`, unit creation helpers, and service lifecycle utilities.
- `http.sh` — download helpers, API call wrappers with retries, and GitHub release discovery.
- `systemd::safe_systemctl args...` — Run `systemctl` with timeout protection (container-friendly).
- `systemd::service_exists name` / `systemd::detect_service_name …` — Inspect available unit files.
- `systemd::create_service path [mode]` — Write a unit file from stdin (respects dry-run).
- `systemd::enable_and_start name` / `systemd::restart name` — Common service workflows.
- `http::download --url URL --output FILE [...]` — Robust curl/wget download helper with retries.
- `http::api_call --url URL [...]` — Token-authenticated API invocation; prints response body.
- `http::get_github_latest_release owner/repo` — Fetch latest GitHub release tag.
- `http::parse_bool value` — Normalize truthy/falsy strings.