- Move all backup_*.py files to libtisbackup/drivers/ subdirectory - Move XenAPI.py and copy_vm_xcp.py to drivers/ (driver-specific) - Create drivers/__init__.py with automatic driver imports - Update tisbackup.py imports to use new structure - Add pyvmomi>=8.0.0 as mandatory dependency - Sync requirements.txt with pyproject.toml dependencies - Add pylint>=3.0.0 and pytest-cov>=6.0.0 to dev dependencies - Configure pylint and coverage tools in pyproject.toml - Add conventional commits guidelines to CLAUDE.md - Enhance .gitignore with comprehensive patterns for Python, IDEs, testing, and secrets - Update CLAUDE.md documentation with new structure and tooling Breaking Changes: - Drivers must now be imported from libtisbackup.drivers instead of libtisbackup - All backup driver files relocated to drivers/ subdirectory 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
8.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
TISBackup is a server-side backup orchestration system written in Python. It executes scheduled backups of various data sources (databases, files, VMs) from remote Linux and Windows systems. The project consists of:
- A CLI tool (tisbackup.py) for executing backups, cleanup, and monitoring
- A Flask web GUI (tisbackup_gui.py) for managing backups
- A pluggable backup driver architecture in libtisbackup/
- Task queue system using Huey with Redis (tasks.py, config.py)
- Docker-based deployment with cron scheduling
Development Commands
IMPORTANT: Always use uv run
to execute Python commands in this project.
Dependency Management
# Install dependencies (uses uv)
uv sync --locked
# Update dependencies
uv lock
Linting
# Run ruff linter (fast, primary linter)
uv run ruff check .
# Auto-fix linting issues
uv run ruff check --fix .
# Run pylint (comprehensive static analysis)
uv run pylint libtisbackup/
# Run pylint on specific file
uv run pylint libtisbackup/ssh.py
Testing
# Run all tests
uv run pytest
# Run tests for specific module
uv run pytest tests/test_ssh.py
# Run with verbose output
uv run pytest -v
# Run tests matching a pattern
uv run pytest -k "ssh"
# Run with coverage report
uv run pytest --cov=libtisbackup --cov-report=html --cov-report=term-missing
# Run tests with coverage and show only missing lines
uv run pytest --cov=libtisbackup --cov-report=term-missing
# Generate HTML coverage report (opens in browser)
uv run pytest --cov=libtisbackup --cov-report=html
# Then open htmlcov/index.html
Coverage reports:
- Terminal report: Shows coverage percentage with missing line numbers
- HTML report: Detailed interactive report in
htmlcov/
directory
See tests/README.md for detailed testing documentation.
Running the Application
Web GUI (development):
uv run python tisbackup_gui.py
# Runs on port 8080, requires config at /etc/tis/tisbackup_gui.ini
CLI Commands:
# Run backups
uv run python tisbackup.py -c /etc/tis/tisbackup-config.ini backup
# Run specific backup section
uv run python tisbackup.py -c /etc/tis/tisbackup-config.ini -s section_name backup
# Cleanup old backups
uv run python tisbackup.py -c /etc/tis/tisbackup-config.ini cleanup
# Check backup status (for Nagios)
uv run python tisbackup.py -c /etc/tis/tisbackup-config.ini checknagios
# List available backup drivers
uv run python tisbackup.py listdrivers
Docker
# Build image
docker build . -t tisbackup:latest
# Run via docker compose (see README.md for full setup)
docker compose up -d
Architecture
Core Components
Main Entry Points:
- tisbackup.py - CLI application with argument parsing and action routing (backup, cleanup, checknagios, etc.)
- tisbackup_gui.py - Flask web application providing UI for backup management and status monitoring
- tasks.py - Huey task definitions for async operations (export_backup)
Backup Driver System:
All backup logic is implemented via driver classes in libtisbackup/drivers/:
- Base class:
backup_generic
in base_driver.py (abstract) - Each driver inherits from
backup_generic
and implements specific backup logic - Drivers are registered via the
register_driver()
decorator function - Configuration is read from INI files using the
read_config()
method - All driver implementations are in libtisbackup/drivers/ subdirectory
Library Modules:
- base_driver.py - Core
backup_generic
class, driver registry, Nagios states - database.py -
BackupStat
class for SQLite operations - ssh.py - SSH utilities with modern key support (Ed25519, ECDSA, RSA)
- process.py - Process execution and monitoring utilities
- utils.py - Date/time formatting, number formatting, validation helpers
- init.py - Package exports for backward compatibility
- drivers/ - All backup driver implementations
Available Drivers:
backup_rsync
/backup_rsync_ssh
- File-based backups via rsyncbackup_rsync_btrfs
/backup_rsync__btrfs_ssh
- Btrfs snapshot-based backupsbackup_mysql
- MySQL database dumpsbackup_pgsql
- PostgreSQL database dumpsbackup_oracle
- Oracle database backupsbackup_sqlserver
- SQL Server backupsbackup_samba4
- Samba4 AD backupsbackup_xva
/backup_xcp_metadata
/copy_vm_xcp
- XenServer VM backupsbackup_vmdk
- VMware VMDK backups (requires pyVmomi)backup_switch
- Network switch configuration backupsbackup_null
- No-op driver for testing
State Management:
- SQLite database tracks backup history, status, and statistics
BackupStat
class in common.py handles DB operations- Database location:
{backup_base_dir}/log/tisbackup.sqlite
Configuration
Two separate INI configuration files:
-
tisbackup-config.ini - Backup definitions
[global]
section with defaults (backup_base_dir, backup_retention_time, maximum_backup_age)- One section per backup job with driver type and parameters
-
tisbackup_gui.ini - GUI settings
- Points to tisbackup-config.ini location(s)
- Defines admin email, base directories
Task Queue
- Uses Huey (Redis-backed) for async job processing
- Currently implements
run_export_backup
for exporting backups to external storage - Task state tracked in tasks.sqlite
Docker Deployment
Two-container architecture:
- tisbackup_gui: Runs Flask web interface
- tisbackup_cron: Runs scheduled backups via cron (executes backup.sh at 03:59 daily)
Code Style
- Line length: 140 characters (configured in pyproject.toml)
- Ruff ignores: F401, F403, F405, E402, E701, E722, E741
- Python 3.13+ required
Commit Message Guidelines
IMPORTANT: This project uses Conventional Commits format.
All commit messages must follow this format:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
Types:
feat
: A new featurefix
: A bug fixdocs
: Documentation only changesrefactor
: Code change that neither fixes a bug nor adds a featuretest
: Adding missing tests or correcting existing testschore
: Changes to build process or auxiliary toolsperf
: Performance improvementsstyle
: Code style changes (formatting, missing semicolons, etc.)
Scopes (commonly used):
auth
: Authentication/authorization changessecurity
: Security-related changesdrivers
: Backup driver changesgui
: Web GUI changesapi
: API changesreadme
: README.md changesclaude
: CLAUDE.md changescore
: Core library changes
Examples:
feat(auth): add pluggable authentication system for Flask routes
fix(security): replace os.popen/os.system with subprocess
docs(readme): add comprehensive security and authentication documentation
refactor(drivers): organize backup modules into drivers subfolder
chore(deps): add pyvmomi as mandatory dependency
Breaking Changes:
Add !
after type/scope for breaking changes:
feat(api)!: remove deprecated endpoint
Note: Always include a scope in parentheses, even for documentation changes.
When Claude Code creates commits, it will automatically follow this format.
Important Patterns
Adding a new backup driver:
- Create
backup_<type>.py
in libtisbackup/drivers/ - Inherit from
backup_generic
- Set class attributes:
type
,required_params
,optional_params
- Implement abstract methods:
do_backup()
,cleanup()
,checknagios()
- Register with
register_driver(backup_<type>)
- Import in libtisbackup/drivers/init.py
SSH Operations:
- Uses paramiko for SSH connections
- Supports both RSA and DSA keys
- Private key path specified per backup section via
private_key
parameter - Pre/post-exec hooks run remote commands via SSH
Path Handling:
- Module imports use sys.path manipulation to include lib/ and libtisbackup/
- All backup drivers expect absolute paths for backup_dir
- Backup directory structure:
{backup_base_dir}/{section_name}/{timestamp}/