Skip to content

Commit 12432d3

Browse files
committed
Linux Directory Backup Script: Initial Release
1 parent c7e7c46 commit 12432d3

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed

Linux/Directory Backup/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Directory Backup Script
2+
3+
This script is a utility for backing up directories in a Linux environment. It allows you to create backups of specified directories, with options for compression, exclusion, scheduling, and retention policies.
4+
5+
## Features
6+
- Automated directory backups
7+
- Compression options
8+
- Configurable backup schedules
9+
- Configurable list of excluded directories
10+
- Customizable retention policies
11+
- Detailed logging
12+
13+
## Getting Started
14+
15+
The scripts requires specific packages (See [Prerequisites](#prerequisites) for more information).
16+
17+
### Prerequisites
18+
19+
This tool uses builtin [Python 3](https://www.python.org/) packages:
20+
21+
* subprocess
22+
* requests
23+
* os
24+
* logging
25+
* socket
26+
* gzip
27+
* datetime
28+
* Path
29+
30+
## Configuration
31+
32+
Each database backup script can be configured using the following variables:
33+
34+
| Variable | Variable Type | Description | Is Required |
35+
|-------------------|---------------|------------------------------------------------------------------------------------------|------------------------|
36+
| `BACKUP_DIR` | `Path` | Sets the root directory for backups and logs | Yes |
37+
| `LOG_DIR` | `Path` | Sets the logs directory name (automatically populated if not specified) | No (Auto Populated) |
38+
| `LOG_FILE_PREFIX` | `str` | Sets the prefix for the log files | Yes |
39+
| `SLACK_WEBHOOK` | `str` | Slack WebHook URL for error notifications | No (Works w/o it) |
40+
| `MAX_BACKUPS` | `int` | Maximum number of backup files to retain | Yes |
41+
| `INCLUDE_PATHS` | `list[str]` | List of directories to backup (Absolute paths must be used) | Yes |
42+
| `EXCLUDE_PATHS` | `list[str]` | List of directories to exclude from backup (Absolute paths must be used) | No |
43+
44+
## Usage
45+
46+
To run this script you need to issue the following commands:
47+
48+
```properties
49+
./path/to/main.py
50+
# or
51+
python3 /path/to/main.py
52+
```

Linux/Directory Backup/main.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/usr/bin/python3
2+
3+
#
4+
## Script Name: System Configuration Backup Script
5+
## Author: unkn0wnAPI [https://github.com/unkn0wnAPI]
6+
## Information: Automated script that backs up Linux directories (for use in a cron job)
7+
#
8+
9+
#
10+
## Imports
11+
#
12+
from datetime import datetime
13+
from pathlib import Path
14+
import subprocess
15+
import logging
16+
import socket
17+
import requests
18+
import os
19+
20+
#
21+
## Init configuration variable
22+
#
23+
BACKUP_DIR = Path("/mnt/your_backup_directory")
24+
LOG_DIR = BACKUP_DIR / "logs"
25+
LOG_FILE_PREFIX = "backup"
26+
SLACK_WEBHOOK = "https://hooks.slack.com/services/your/webhook/url"
27+
MAX_BACKUPS = 7
28+
INCLUDE_PATHS = ["/dir1", "/dir2"] # Directories to include [absolute paths]
29+
EXCLUDE_PATHS = ["/dir1/exclude", "/dir2/exclude"] # Directories to exclude [absolute paths]
30+
31+
#
32+
## Core Logging Setup
33+
#
34+
os.makedirs(LOG_DIR, exist_ok=True)
35+
logging.basicConfig(
36+
filename=LOG_DIR / f'{LOG_FILE_PREFIX}_{datetime.now().strftime("%Y-%m-%d")}.log',
37+
level=logging.INFO,
38+
format='%(asctime)s - %(levelname)s - %(message)s'
39+
)
40+
41+
#
42+
## Core Functions
43+
#
44+
def notify_slack(message):
45+
payload = {
46+
"text": "<!channel>",
47+
"attachments": [
48+
{
49+
"color": '#FF0000',
50+
"text": message,
51+
"footer": "System Backup",
52+
"ts": int(datetime.now().timestamp())
53+
}
54+
]
55+
}
56+
try:
57+
requests.post(SLACK_WEBHOOK, json=payload)
58+
except Exception as e:
59+
logging.error(f"Slack notification failed: {e}")
60+
61+
def shell_exec(command, description):
62+
logging.info(f"Running: {description}")
63+
try:
64+
result = subprocess.run(command, shell=True, check=True, capture_output=True)
65+
logging.info(result.stdout.decode())
66+
return True
67+
except subprocess.CalledProcessError as e:
68+
logging.error(f"{description} failed:\n{e.stderr.decode()}")
69+
notify_slack(f"System backup error: {description} failed on {socket.gethostname()}")
70+
return False
71+
72+
def rotate_backups(backup_dir, hostname):
73+
backups = sorted(
74+
backup_dir.glob(f"{hostname}-*.tgz"),
75+
key=os.path.getmtime,
76+
reverse=True
77+
)
78+
79+
for old_backup in backups[MAX_BACKUPS:]:
80+
try:
81+
old_backup.unlink()
82+
logging.info(f"Deleted old backup: {old_backup}")
83+
except Exception as e:
84+
logging.error(f"Failed to delete old backup {old_backup}: {e}")
85+
86+
#
87+
## Script Start point
88+
#
89+
def main():
90+
hostname = socket.gethostname()
91+
date_str = datetime.now().strftime('%d-%m-%Y')
92+
backup_file = BACKUP_DIR / f"{hostname}-{date_str}.tgz"
93+
94+
os.makedirs(BACKUP_DIR, exist_ok=True)
95+
96+
# Build tar command with exclusions
97+
exclude_args = " ".join([f"--exclude='{path}'" for path in EXCLUDE_PATHS])
98+
tar_command = f"tar -zcpvf {backup_file} {exclude_args} {' '.join(INCLUDE_PATHS)}"
99+
100+
if not shell_exec(tar_command, "Docker data tar backup"):
101+
return 1
102+
103+
# Check backup file
104+
if not backup_file.exists() or backup_file.stat().st_size == 0:
105+
logging.error("Backup file is empty or missing.")
106+
notify_slack(f"Docker backup failed: Archive is empty or missing on {hostname}")
107+
return 1
108+
109+
# Rotate old backups
110+
rotate_backups(BACKUP_DIR, hostname)
111+
logging.info("Backup rotation completed successfully.")
112+
logging.info("Docker backup completed successfully.")
113+
114+
if __name__ == "__main__":
115+
main()

0 commit comments

Comments
 (0)