Skip to content

Commit

Permalink
Added urbackup support
Browse files Browse the repository at this point in the history
  • Loading branch information
judahpaul16 committed Apr 27, 2024
1 parent 4946f95 commit c8f92b5
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.2.2
current_version = 0.2.3
commit = True
tag = True

Expand Down
59 changes: 56 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

## Features

- **File Organization**: Automatically move files based on their extension from one directory to another.
- **Notification System** (Future Feature): Get notified regarding specific events specified in the configuration file.
- **Automated Backups** (Future Feature): Set up scheduled backups for important directories.
- [x] **File Organization**: Automatically move files based on their extension from one directory to another.
- [x] **Automated Backups**: Set up scheduled backups for important directories using [urbackup](https://github.com/uroni/urbackup-server-python-web-api-wrapper).
- [ ] **Notification System**: Get notified regarding specific events specified in the configuration file.

## Installation

Expand All @@ -35,6 +35,18 @@ tasks:
destination: /path/to/your/destination/for/images
- extension: .pdf
destination: /path/to/your/destination/for/documents
backup:
- name: Backup Important Files
type: incremental-file # incremental-image, full-file, full-image
schedule: daily # weekly, monthly
retention: 7 # number of days to keep backups
connection:
server: http://your-backup-server:55414
username: foo
password: bar
directories:
- /path/to/your/important/directory
- /path/to/another/important/directory
```
## Usage
Expand Down Expand Up @@ -98,6 +110,47 @@ For long-term operation or deployment, integrating **dirconfig** with system ser

**dirconfig** welcomes enhancements and customization. If you're interested in adding new features or improving the tool, consider contributing to the source code. Your input and contributions are highly appreciated.

## Urbackup Documentation
For more information on the Urbackup API, please refer to these resources:
* *[Urbackup Python API Wrapper](https://github.com/uroni/urbackup-server-python-web-api-wrapper)*
* *[Urbackup Backend ClientCTL](https://github.com/uroni/urbackup_backend/tree/dev/clientctl)*

Command Line Options for `urbackupclientctl` are as follows:
```sh
USAGE:
urbackupclientctl [--help] [--version] <command> [<args>]
Get specific command help with urbackupclientctl <command> --help
urbackupclientctl start
Start an incremental/full image/file backup
urbackupclientctl status
Get current backup status
urbackupclientctl browse
Browse backups and files/folders in backups
urbackupclientctl restore-start
Restore files/folders from backup
urbackupclientctl set-settings
Set backup settings
urbackupclientctl reset-keep
Reset keeping files during incremental backups
urbackupclientctl add-backupdir
Add new directory to backup set
urbackupclientctl list-backupdirs
List directories that are being backed up
urbackupclientctl remove-backupdir
Remove directory from backup set
```

## License

**dirconfig** is licensed under the MIT License. See the `LICENSE` file for more details.
14 changes: 13 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,16 @@ tasks:
- extension: .jpg
destination: /images
- extension: .pdf
destination: /documents
destination: /documents
# backup:
# - name: Backup Important Files
# type: incremental-file # incremental-image, full-file, full-image
# schedule: daily # weekly, monthly
# retention: 7 # number of days to keep backups
# connection:
# server: http://your-backup-server:55414
# username: foo
# password: bar
# directories:
# - /path/to/your/important/directory
# - /path/to/another/important/directory
85 changes: 83 additions & 2 deletions dirconfig/main.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
from urbackup_api import urbackup_server, installer_os
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
from pathlib import Path
from threading import Thread, Event
import subprocess
import argparse
import logging
import signal
import shutil
import time
import yaml
import sys
import os

# Global variables
observer = None
PID_FILE = 'dirconfig.pid'
backup_thread = None # Thread for backup scheduling
shutdown_event = Event() # Event to signal shutdown to backup thread
PID_FILE = 'dirconfig.pid' # Default PID file path

class ChangeHandler(FileSystemEventHandler):
def __init__(self, tasks):
Expand Down Expand Up @@ -68,19 +74,94 @@ def signal_handler(signum, frame):
os.remove(PID_FILE)
sys.exit(0)

def check_and_install_urbackup_client(backup_config):
stdout, stderr, returncode = subprocess.run(["urbackupclientctl", "status"], capture_output=True, text=True)
if returncode != 0:
print("UrBackup client not running. Attempting installation...")
logging.info("UrBackup client not running. Attempting installation...")
# Determine OS type for choosing the correct installer
os_type = installer_os.Linux if os.name != 'nt' else installer_os.Windows
installer_filename = "urbackup_client_installer" + (".exe" if os_type == installer_os.Windows else "")
backup_server = urbackup_server(
server_url=backup_config['connection']['server'],
server_username=backup_config['connection']['username'],
server_password=backup_config['connection']['password']
)
if backup_server.login():
client_name = f"{backup_config['name']}-dirconfig"
if backup_server.download_installer(installer_filename, client_name, os_type):
if os.name != 'nt':
subprocess.run(["chmod", "+x", installer_filename]) # Make executable on Unix/Linux
subprocess.run([f"./{installer_filename}"]) # Execute installer
print("Installation successful.")
logging.info("Installation successful.")
else:
print("Failed to download installer.")
logging.error("Failed to download installer.")
else:
print("Failed to log in to the backup server.")
logging.error("Failed to log in to the backup server.")
else:
print("UrBackup client is running.")
logging.info("UrBackup client is running.")

def setup_backup_dirs(backup_config):
"""Add directories specified in config to UrBackup."""
for directory in backup_config['directories']:
cmd = ["urbackupclientctl", "add-backupdir", "--path", directory]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"Successfully added backup directory: {directory}")
logging.info(f"Successfully added backup directory: {directory}")
else:
print(f"Failed to add backup directory: {directory}. Error: {result.stderr}")
logging.error(f"Failed to add backup directory: {directory}. Error: {result.stderr}")

def initiate_backup(backup_type, client_name):
"""Initiate the backup process using the urbackupclientctl command with detailed options."""
if 'incremental' in backup_type:
backup_option = '-i'
else:
backup_option = '-f'

cmd = [
"urbackupclientctl", "start", backup_option,
"--non-blocking", "--client", client_name
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"Successfully started {backup_type} backup for {client_name}.")
logging.info(f"Successfully started {backup_type} backup for {client_name}.")
else:
print(f"Failed to start {backup_type} backup for {client_name}. Error: {result.stderr}")
logging.error(f"Failed to start {backup_type} backup for {client_name}. Error: {result.stderr}")

def backup_task(backup_config):
"""Performs the entire backup task from checking/installing client to starting backups."""
check_and_install_urbackup_client(backup_config)
setup_backup_dirs(backup_config)
initiate_backup(backup_config['type'])

def start_daemon(config_path):
global observer
config = load_config(config_path)
tasks = config['tasks']
observer = Observer()

for task in tasks:
if task['type'] == 'file-organization':
observer.schedule(ChangeHandler(tasks), os.path.abspath(task['source']), recursive=True)

# Start backup scheduling in a separate thread if 'backup' is defined in the config
if 'backup' in config:
backup_thread = Thread(target=backup_task, args=(config,))
backup_thread.start()

# Register the signal handler for SIGINT
signal.signal(signal.SIGINT, signal_handler)

observer.start()

with open(PID_FILE, 'w') as f:
f.write(str(os.getpid()))

Expand Down
Binary file modified requirements.txt
Binary file not shown.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="dirconfig",
version="0.2.2",
version="0.2.3",
author="Judah Paul",
author_email="me@judahpaul.com",
description="A simple directory configuration tool",
Expand Down

0 comments on commit c8f92b5

Please sign in to comment.