Architecture¶
fnb is a modular Python package designed for efficient backup workflows. This page explains the core design and implementation details.
Overall Structure¶
fnb consists of the following main components:
src/fnb/
├── __init__.py # Package initialization and version
├── backuper.py # Backup execution logic
├── cli.py # Command-line interface with Typer
├── config.py # Configuration models with Pydantic
├── env.py # Environment variable handling
├── fetcher.py # Fetch execution logic
├── gear.py # Core rsync execution utilities
├── generator.py # Configuration file generation
└── reader.py # Configuration discovery and loading
Component Overview¶
CLI Interface (cli.py)¶
The command-line interface built with Typer framework that provides:
- Main Commands:
fetch,backup,sync,init,status,version - Argument Validation: Type checking and error handling
- Delegate Pattern: Routes commands to appropriate modules
- User Feedback: Progress messages and error reporting
Key design principles: - Single responsibility for each command - Consistent error handling across all commands - Help documentation integrated into command definitions
Configuration Models (config.py)¶
Pydantic-based data models for type-safe configuration:
RsyncTaskConfig¶
Represents a single rsync task with validation:
@dataclass
class RsyncTaskConfig:
label: str # Unique task identifier
summary: str # Human-readable description
host: str # SSH host or "none" for local
source: str # Source path
target: str # Target path
options: list[str] # rsync options
enabled: bool # Task activation status
FnbConfig¶
Top-level configuration container:
class FnbConfig(BaseModel):
fetch: dict[str, RsyncTaskConfig] = {}
backup: dict[str, RsyncTaskConfig] = {}
def get_task_by_label(self, section: str, label: str) -> RsyncTaskConfig | None
def get_enabled_tasks(self, section: str) -> list[RsyncTaskConfig]
Configuration Discovery (reader.py)¶
Handles configuration file discovery and loading:
ConfigReader¶
Main configuration management class:
- Auto-discovery: Searches multiple standard locations
- Environment Expansion: Supports
$HOME,${VAR}syntax - Validation: TOML parsing and schema validation
- Status Reporting: Configuration overview and diagnostics
Search order:
1. ./fnb.toml (project-local)
2. ./config.toml
3. ./config/*.toml (split configurations)
4. ~/.config/fnb/config.toml (user configuration)
5. Platform-specific user directories
Core Execution Engine (gear.py)¶
The heart of fnb's backup operations:
run_rsync()¶
Main execution function with features:
- SSH Password Automation: Uses
pexpectfor password handling - Process Management: Signal handling and cleanup
- Error Detection: rsync exit code interpretation
- Dry-run Support: Preview mode for all operations
SSH Automation¶
Implements secure SSH password handling:
def run_rsync(task: RsyncTaskConfig,
dry_run: bool = False,
ssh_password: str | None = None,
create_dirs: bool = False) -> None
Key features: - Timeout handling for SSH connections - Secure password masking in logs - Signal-based process termination - Comprehensive error reporting
Task Execution Modules¶
Fetcher (fetcher.py)¶
Handles remote-to-local data retrieval:
- Validates remote connectivity
- Manages SSH authentication
- Creates local target directories
- Delegates to
gear.run_rsync()
Backuper (backuper.py)¶
Handles local-to-external backup operations:
- Validates local source paths
- Creates backup target directories
- Supports various backup destinations
- Delegates to
gear.run_rsync()
Utility Modules¶
Environment Handler (env.py)¶
Manages environment variables and secrets:
- Password Discovery: Multiple
.envfile locations - Variable Normalization: Hostname to env var mapping
- Secure Loading: Uses
python-dotenvfor parsing - Fallback Strategy: Command-line →
.env→ prompt
Configuration Generator (generator.py)¶
Creates initial configuration files:
- Template System: Predefined configuration templates
- File Type Support: Generates
fnb.tomland.envfiles - Interactive Mode: User prompts for configuration
- Force Overwrite: Option to replace existing files
Data Flow Architecture¶
1. Command Processing Flow¶
graph TD
A[User Command] --> B[CLI Parser]
B --> C[Config Discovery]
C --> D[Task Resolution]
D --> E[Execution Module]
E --> F[Core Engine]
F --> G[rsync Process]
2. Configuration Loading¶
graph TD
A[Config Request] --> B[Path Discovery]
B --> C[TOML Parsing]
C --> D[Schema Validation]
D --> E[Env Expansion]
E --> F[Task Objects]
3. Sync Workflow¶
graph TD
A[Sync Command] --> B[Fetch Task]
B --> C[SSH Connection]
C --> D[Remote → Local]
D --> E[Backup Task]
E --> F[Local → External]
F --> G[Complete]
Design Principles¶
Modularity¶
- Each module has a single, well-defined responsibility
- Clear interfaces between components
- Minimal coupling between modules
- Easy to test and maintain
Type Safety¶
- Comprehensive type hints throughout codebase
- Pydantic for runtime type validation
- mypy compatibility for static analysis
- Clear error messages for type mismatches
Error Handling¶
- Consistent error reporting across modules
- User-friendly error messages
- Graceful degradation when possible
- Detailed logging for debugging
Extensibility¶
- Plugin-like architecture for new task types
- Configuration-driven behavior
- Easy addition of new rsync options
- Support for custom validation rules
Security Considerations¶
Password Handling¶
- Passwords never stored in plaintext files
- Environment variable isolation
- Process memory cleanup
- Secure inter-process communication
Path Validation¶
- Prevention of directory traversal attacks
- Validation of local vs. remote paths
- Safe expansion of environment variables
- Protection against malicious rsync options
Process Security¶
- Controlled subprocess execution
- Signal handling for clean termination
- Resource cleanup on errors
- Minimal privilege requirements
Performance Characteristics¶
Memory Usage¶
- Minimal memory footprint (< 10MB typical)
- Streaming-based file operations
- Efficient configuration caching
- Low overhead for multiple tasks
Execution Speed¶
- Fast configuration loading (< 100ms)
- Parallel-ready architecture
- Minimal startup overhead
- Efficient rsync delegation
Scalability¶
- Handles hundreds of tasks efficiently
- Configuration file size not a bottleneck
- Suitable for automated/scripted usage
- Resource usage scales linearly
Testing Architecture¶
Test Structure¶
tests/
├── unit/ # Component isolation tests
├── integration/ # End-to-end workflow tests
└── fixtures/ # Shared test utilities
Test Strategy¶
- Unit Tests: Individual module validation
- Integration Tests: Complete workflow validation
- Mocking Strategy: External dependency isolation
- Coverage Target: 85%+ code coverage
Key Test Areas¶
- Configuration validation and error cases
- SSH authentication scenarios
- File system operations
- Error propagation and handling
- CLI argument processing
Future Architecture Considerations¶
Planned Improvements¶
- Plugin system for custom backup destinations
- Configuration templating and inheritance
- Enhanced progress reporting and logging
- Support for parallel task execution
Extension Points¶
- Custom rsync option validators
- Alternative SSH authentication methods
- Integration with cloud storage APIs
- Configuration management via web interface
This architecture provides a solid foundation for reliable, secure, and maintainable backup workflows while remaining simple enough for individual users and robust enough for production environments.