Remove daemon mode references and unused config fields
The --daemon flag, BackupInterval, FullScanInterval, MinTimeBetweenRun config fields, and DirtyPath model were placeholders for a never-shipped daemon mode and have been removed. Daemon mode is out of scope for 1.0.
This commit is contained in:
22
README.md
22
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
WIP: pre-1.0, some functions may not be fully implemented yet
|
WIP: pre-1.0, some functions may not be fully implemented yet
|
||||||
|
|
||||||
`vaultik` is an incremental backup daemon written in Go. It encrypts data
|
`vaultik` is an incremental backup tool written in Go. It encrypts data
|
||||||
using an `age` public key and uploads each encrypted blob directly to a
|
using an `age` public key and uploads each encrypted blob directly to a
|
||||||
remote S3-compatible object store. It requires no private keys, secrets, or
|
remote S3-compatible object store. It requires no private keys, secrets, or
|
||||||
credentials (other than those required to PUT to encrypted object storage,
|
credentials (other than those required to PUT to encrypted object storage,
|
||||||
@@ -120,9 +120,6 @@ passphrase is needed or stored locally.
|
|||||||
access_key_id: ...
|
access_key_id: ...
|
||||||
secret_access_key: ...
|
secret_access_key: ...
|
||||||
region: us-east-1
|
region: us-east-1
|
||||||
backup_interval: 1h
|
|
||||||
full_scan_interval: 24h
|
|
||||||
min_time_between_run: 15m
|
|
||||||
chunk_size: 10MB
|
chunk_size: 10MB
|
||||||
blob_size_limit: 1GB
|
blob_size_limit: 1GB
|
||||||
```
|
```
|
||||||
@@ -147,16 +144,21 @@ passphrase is needed or stored locally.
|
|||||||
### commands
|
### commands
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
vaultik [--config <path>] snapshot create [snapshot-names...] [--cron] [--daemon] [--prune]
|
vaultik [--config <path>] snapshot create [snapshot-names...] [--cron] [--prune] [--skip-errors]
|
||||||
vaultik [--config <path>] snapshot list [--json]
|
vaultik [--config <path>] snapshot list [--json]
|
||||||
vaultik [--config <path>] snapshot verify <snapshot-id> [--deep]
|
vaultik [--config <path>] snapshot verify <snapshot-id> [--deep] [--json]
|
||||||
vaultik [--config <path>] snapshot purge [--keep-latest | --older-than <duration>] [--force]
|
vaultik [--config <path>] snapshot purge [--keep-latest | --older-than <duration>] [--force]
|
||||||
vaultik [--config <path>] snapshot remove <snapshot-id> [--dry-run] [--force]
|
vaultik [--config <path>] snapshot remove <snapshot-id|--all> [--dry-run] [--force] [--remote] [--json]
|
||||||
vaultik [--config <path>] snapshot prune
|
vaultik [--config <path>] snapshot prune
|
||||||
vaultik [--config <path>] restore <snapshot-id> <target-dir> [paths...]
|
vaultik [--config <path>] restore <snapshot-id> <target-dir> [paths...] [--verify]
|
||||||
vaultik [--config <path>] prune [--dry-run] [--force]
|
vaultik [--config <path>] prune [--force] [--json]
|
||||||
|
vaultik [--config <path>] purge [--keep-latest | --older-than <duration>] [--force]
|
||||||
|
vaultik [--config <path>] verify <snapshot-id> [--deep] [--json]
|
||||||
vaultik [--config <path>] info
|
vaultik [--config <path>] info
|
||||||
|
vaultik [--config <path>] remote info [--json]
|
||||||
vaultik [--config <path>] store info
|
vaultik [--config <path>] store info
|
||||||
|
vaultik [--config <path>] database purge [--force]
|
||||||
|
vaultik version
|
||||||
```
|
```
|
||||||
|
|
||||||
### environment
|
### environment
|
||||||
@@ -170,8 +172,8 @@ vaultik [--config <path>] store info
|
|||||||
* Config is located at `/etc/vaultik/config.yml` by default
|
* Config is located at `/etc/vaultik/config.yml` by default
|
||||||
* Optional snapshot names argument to create specific snapshots (default: all)
|
* Optional snapshot names argument to create specific snapshots (default: all)
|
||||||
* `--cron`: Silent unless error (for crontab)
|
* `--cron`: Silent unless error (for crontab)
|
||||||
* `--daemon`: Run continuously with inotify monitoring and periodic scans
|
|
||||||
* `--prune`: Delete old snapshots and orphaned blobs after backup
|
* `--prune`: Delete old snapshots and orphaned blobs after backup
|
||||||
|
* `--skip-errors`: Skip file read errors (log them loudly but continue)
|
||||||
|
|
||||||
**snapshot list**: List all snapshots with their timestamps and sizes
|
**snapshot list**: List all snapshots with their timestamps and sizes
|
||||||
* `--json`: Output in JSON format
|
* `--json`: Output in JSON format
|
||||||
|
|||||||
23
TODO.md
23
TODO.md
@@ -103,26 +103,3 @@ User must have rclone configured separately (via `rclone config`).
|
|||||||
- Ensure consistent code style
|
- Ensure consistent code style
|
||||||
|
|
||||||
1. Tag and release v1.0.0
|
1. Tag and release v1.0.0
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Post-1.0 (Daemon Mode)
|
|
||||||
|
|
||||||
1. Implement inotify file watcher for Linux
|
|
||||||
- Watch source directories for changes
|
|
||||||
- Track dirty paths in memory
|
|
||||||
|
|
||||||
1. Implement FSEvents watcher for macOS
|
|
||||||
- Watch source directories for changes
|
|
||||||
- Track dirty paths in memory
|
|
||||||
|
|
||||||
1. Implement backup scheduler in daemon mode
|
|
||||||
- Respect backup_interval config
|
|
||||||
- Trigger backup when dirty paths exist and interval elapsed
|
|
||||||
- Implement full_scan_interval for periodic full scans
|
|
||||||
|
|
||||||
1. Add proper signal handling for daemon
|
|
||||||
- Graceful shutdown on SIGTERM/SIGINT
|
|
||||||
- Complete in-progress backup before exit
|
|
||||||
|
|
||||||
1. Write tests for daemon mode
|
|
||||||
|
|||||||
@@ -291,21 +291,6 @@ storage_url: "rclone://las1stor1//srv/pool.2024.04/backups/heraklion"
|
|||||||
# # Default: 5MB
|
# # Default: 5MB
|
||||||
# #part_size: 5MB
|
# #part_size: 5MB
|
||||||
|
|
||||||
# How often to run backups in daemon mode
|
|
||||||
# Format: 1h, 30m, 24h, etc
|
|
||||||
# Default: 1h
|
|
||||||
#backup_interval: 1h
|
|
||||||
|
|
||||||
# How often to do a full filesystem scan in daemon mode
|
|
||||||
# Between full scans, inotify is used to detect changes
|
|
||||||
# Default: 24h
|
|
||||||
#full_scan_interval: 24h
|
|
||||||
|
|
||||||
# Minimum time between backup runs in daemon mode
|
|
||||||
# Prevents backups from running too frequently
|
|
||||||
# Default: 15m
|
|
||||||
#min_time_between_run: 15m
|
|
||||||
|
|
||||||
# Path to local SQLite index database
|
# Path to local SQLite index database
|
||||||
# This database tracks file state for incremental backups
|
# This database tracks file state for incremental backups
|
||||||
# Default: /var/lib/vaultik/index.sqlite
|
# Default: /var/lib/vaultik/index.sqlite
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func NewRootCommand() *cobra.Command {
|
|||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "vaultik",
|
Use: "vaultik",
|
||||||
Short: "Secure incremental backup tool with asymmetric encryption",
|
Short: "Secure incremental backup tool with asymmetric encryption",
|
||||||
Long: `vaultik is a secure incremental backup daemon that encrypts data using age
|
Long: `vaultik is a secure incremental backup tool that encrypts data using age
|
||||||
public keys and uploads to S3-compatible storage. No private keys are needed
|
public keys and uploads to S3-compatible storage. No private keys are needed
|
||||||
on the source system.`,
|
on the source system.`,
|
||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ specifying a path using --config or by setting VAULTIK_CONFIG to a path.`,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolVar(&opts.Daemon, "daemon", false, "Run in daemon mode with inotify monitoring")
|
|
||||||
cmd.Flags().BoolVar(&opts.Cron, "cron", false, "Run in cron mode (silent unless error)")
|
cmd.Flags().BoolVar(&opts.Cron, "cron", false, "Run in cron mode (silent unless error)")
|
||||||
cmd.Flags().BoolVar(&opts.Prune, "prune", false, "Delete all previous snapshots and unreferenced blobs after backup")
|
cmd.Flags().BoolVar(&opts.Prune, "prune", false, "Delete all previous snapshots and unreferenced blobs after backup")
|
||||||
cmd.Flags().BoolVar(&opts.SkipErrors, "skip-errors", false, "Skip file read errors (log them loudly but continue)")
|
cmd.Flags().BoolVar(&opts.SkipErrors, "skip-errors", false, "Skip file read errors (log them loudly but continue)")
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
"git.eeqj.de/sneak/smartconfig"
|
"git.eeqj.de/sneak/smartconfig"
|
||||||
@@ -85,14 +84,11 @@ func (c *Config) SnapshotNames() []string {
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
AgeRecipients []string `yaml:"age_recipients"`
|
AgeRecipients []string `yaml:"age_recipients"`
|
||||||
AgeSecretKey string `yaml:"age_secret_key"`
|
AgeSecretKey string `yaml:"age_secret_key"`
|
||||||
BackupInterval time.Duration `yaml:"backup_interval"`
|
|
||||||
BlobSizeLimit Size `yaml:"blob_size_limit"`
|
BlobSizeLimit Size `yaml:"blob_size_limit"`
|
||||||
ChunkSize Size `yaml:"chunk_size"`
|
ChunkSize Size `yaml:"chunk_size"`
|
||||||
Exclude []string `yaml:"exclude"` // Global excludes applied to all snapshots
|
Exclude []string `yaml:"exclude"` // Global excludes applied to all snapshots
|
||||||
FullScanInterval time.Duration `yaml:"full_scan_interval"`
|
|
||||||
Hostname string `yaml:"hostname"`
|
Hostname string `yaml:"hostname"`
|
||||||
IndexPath string `yaml:"index_path"`
|
IndexPath string `yaml:"index_path"`
|
||||||
MinTimeBetweenRun time.Duration `yaml:"min_time_between_run"`
|
|
||||||
S3 S3Config `yaml:"s3"`
|
S3 S3Config `yaml:"s3"`
|
||||||
Snapshots map[string]SnapshotConfig `yaml:"snapshots"`
|
Snapshots map[string]SnapshotConfig `yaml:"snapshots"`
|
||||||
CompressionLevel int `yaml:"compression_level"`
|
CompressionLevel int `yaml:"compression_level"`
|
||||||
@@ -157,9 +153,6 @@ func Load(path string) (*Config, error) {
|
|||||||
// Set defaults
|
// Set defaults
|
||||||
BlobSizeLimit: Size(10 * 1024 * 1024 * 1024), // 10GB
|
BlobSizeLimit: Size(10 * 1024 * 1024 * 1024), // 10GB
|
||||||
ChunkSize: Size(10 * 1024 * 1024), // 10MB
|
ChunkSize: Size(10 * 1024 * 1024), // 10MB
|
||||||
BackupInterval: 1 * time.Hour,
|
|
||||||
FullScanInterval: 24 * time.Hour,
|
|
||||||
MinTimeBetweenRun: 15 * time.Minute,
|
|
||||||
IndexPath: filepath.Join(xdg.DataHome, appName, "index.sqlite"),
|
IndexPath: filepath.Join(xdg.DataHome, appName, "index.sqlite"),
|
||||||
CompressionLevel: 3,
|
CompressionLevel: 3,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,10 +63,3 @@ type Chunk struct {
|
|||||||
Offset int64
|
Offset int64
|
||||||
Length int64
|
Length int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirtyPath represents a path marked for backup by inotify
|
|
||||||
type DirtyPath struct {
|
|
||||||
Path string
|
|
||||||
MarkedAt time.Time
|
|
||||||
EventType string // "create", "modify", "delete"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -66,18 +66,6 @@ func (v *Vaultik) ShowInfo() error {
|
|||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
// Daemon Settings (if applicable)
|
|
||||||
if v.Config.BackupInterval > 0 || v.Config.MinTimeBetweenRun > 0 {
|
|
||||||
fmt.Printf("=== Daemon Settings ===\n")
|
|
||||||
if v.Config.BackupInterval > 0 {
|
|
||||||
fmt.Printf("Backup Interval: %s\n", v.Config.BackupInterval)
|
|
||||||
}
|
|
||||||
if v.Config.MinTimeBetweenRun > 0 {
|
|
||||||
fmt.Printf("Minimum Time: %s\n", v.Config.MinTimeBetweenRun)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local Database
|
// Local Database
|
||||||
fmt.Printf("=== Local Database ===\n")
|
fmt.Printf("=== Local Database ===\n")
|
||||||
fmt.Printf("Index Path: %s\n", v.Config.IndexPath)
|
fmt.Printf("Index Path: %s\n", v.Config.IndexPath)
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
|
|
||||||
// SnapshotCreateOptions contains options for the snapshot create command
|
// SnapshotCreateOptions contains options for the snapshot create command
|
||||||
type SnapshotCreateOptions struct {
|
type SnapshotCreateOptions struct {
|
||||||
Daemon bool
|
|
||||||
Cron bool
|
Cron bool
|
||||||
Prune bool
|
Prune bool
|
||||||
SkipErrors bool // Skip file read errors (log them loudly but continue)
|
SkipErrors bool // Skip file read errors (log them loudly but continue)
|
||||||
@@ -54,12 +53,6 @@ func (v *Vaultik) CreateSnapshot(opts *SnapshotCreateOptions) error {
|
|||||||
return fmt.Errorf("prune database: %w", err)
|
return fmt.Errorf("prune database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Daemon {
|
|
||||||
log.Info("Running in daemon mode")
|
|
||||||
// TODO: Implement daemon mode with inotify
|
|
||||||
return fmt.Errorf("daemon mode not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine which snapshots to process
|
// Determine which snapshots to process
|
||||||
snapshotNames := opts.Snapshots
|
snapshotNames := opts.Snapshots
|
||||||
if len(snapshotNames) == 0 {
|
if len(snapshotNames) == 0 {
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ s3:
|
|||||||
region: us-east-1
|
region: us-east-1
|
||||||
use_ssl: true
|
use_ssl: true
|
||||||
part_size: 5242880 # 5MB
|
part_size: 5242880 # 5MB
|
||||||
backup_interval: 1h
|
|
||||||
full_scan_interval: 24h
|
|
||||||
min_time_between_run: 15m
|
|
||||||
index_path: /tmp/vaultik-test.sqlite
|
index_path: /tmp/vaultik-test.sqlite
|
||||||
chunk_size: 10MB
|
chunk_size: 10MB
|
||||||
blob_size_limit: 10GB
|
blob_size_limit: 10GB
|
||||||
|
|||||||
@@ -17,9 +17,6 @@ s3:
|
|||||||
region: us-east-1
|
region: us-east-1
|
||||||
use_ssl: false
|
use_ssl: false
|
||||||
part_size: 5242880 # 5MB
|
part_size: 5242880 # 5MB
|
||||||
backup_interval: 1h
|
|
||||||
full_scan_interval: 24h
|
|
||||||
min_time_between_run: 15m
|
|
||||||
index_path: /tmp/vaultik-integration-test.sqlite
|
index_path: /tmp/vaultik-integration-test.sqlite
|
||||||
chunk_size: 10MB
|
chunk_size: 10MB
|
||||||
blob_size_limit: 10GB
|
blob_size_limit: 10GB
|
||||||
|
|||||||
Reference in New Issue
Block a user