Skip to content

Commit 97f756a

Browse files
committed
add initial commands for database restore and backup
1 parent 2c0d361 commit 97f756a

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Management command to backup PostgreSQL database.
3+
4+
Usage:
5+
docker-compose -f local.yml run --rm django python manage.py database_backup
6+
docker-compose -f production.yml run --rm django python manage.py database_backup
7+
"""
8+
9+
import enum
10+
import os
11+
import socket
12+
import subprocess
13+
from datetime import datetime
14+
15+
from django.conf import settings
16+
from django.core.management.base import BaseCommand
17+
18+
19+
class Server(enum.Enum):
20+
PRODUCTION = "PRODUCTION"
21+
STAGING = "STAGING"
22+
UNKNOWN = "UNKNOWN"
23+
24+
25+
def detect_server() -> Server:
26+
hostname = socket.gethostname().upper()
27+
28+
if "PRODUCTION" in hostname:
29+
return Server.PRODUCTION
30+
elif "STAGING" in hostname:
31+
return Server.STAGING
32+
return Server.UNKNOWN
33+
34+
35+
class Command(BaseCommand):
36+
help = "Creates a PostgreSQL backup using pg_dump"
37+
38+
def handle(self, *args, **options):
39+
server = detect_server()
40+
date_str = datetime.now().strftime("%Y%m%d")
41+
backup_file = f"{server.value.lower()}_backup_{date_str}.sql"
42+
43+
db_settings = settings.DATABASES["default"]
44+
host = db_settings["HOST"]
45+
name = db_settings["NAME"]
46+
user = db_settings["USER"]
47+
password = db_settings["PASSWORD"]
48+
49+
cmd = ["pg_dump", "-h", host, "-U", user, "-d", name, "--no-owner", "--no-privileges", "-f", backup_file]
50+
51+
try:
52+
env = os.environ.copy()
53+
env["PGPASSWORD"] = password
54+
subprocess.run(cmd, env=env, check=True)
55+
self.stdout.write(self.style.SUCCESS(f"Successfully created backup for {server.value}: {backup_file}"))
56+
except subprocess.CalledProcessError as e:
57+
self.stdout.write(self.style.ERROR(f"Backup failed on {server.value}: {str(e)}"))
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""
2+
Management command to restore PostgreSQL database.
3+
4+
Usage:
5+
docker-compose -f local.yml run --rm django python manage.py database_restore path/to/backup.sql
6+
docker-compose -f production.yml run --rm django python manage.py database_restore path/to/backup.sql
7+
"""
8+
9+
import enum
10+
import os
11+
import socket
12+
import subprocess
13+
14+
from django.conf import settings
15+
from django.core.management.base import BaseCommand, CommandError
16+
17+
18+
class Server(enum.Enum):
19+
PRODUCTION = "PRODUCTION"
20+
STAGING = "STAGING"
21+
UNKNOWN = "UNKNOWN"
22+
23+
24+
def detect_server() -> Server:
25+
hostname = socket.gethostname().upper()
26+
if "PRODUCTION" in hostname:
27+
return Server.PRODUCTION
28+
elif "STAGING" in hostname:
29+
return Server.STAGING
30+
return Server.UNKNOWN
31+
32+
33+
class Command(BaseCommand):
34+
help = "Restores PostgreSQL database from backup file"
35+
36+
def add_arguments(self, parser):
37+
parser.add_argument("backup_path", type=str, help="Path to the backup file")
38+
39+
def handle(self, *args, **options):
40+
server = detect_server()
41+
backup_path = options["backup_path"]
42+
43+
if not os.path.exists(backup_path):
44+
raise CommandError(f"Backup file not found: {backup_path}")
45+
46+
db_settings = settings.DATABASES["default"]
47+
host = db_settings["HOST"]
48+
name = db_settings["NAME"]
49+
user = db_settings["USER"]
50+
password = db_settings["PASSWORD"]
51+
52+
# Drop and recreate database
53+
drop_cmd = ["psql", "-h", host, "-U", user, "-d", "postgres", "-c", f"DROP DATABASE IF EXISTS {name}"]
54+
create_cmd = ["psql", "-h", host, "-U", user, "-d", "postgres", "-c", f"CREATE DATABASE {name}"]
55+
56+
# Restore command
57+
restore_cmd = ["psql", "-h", host, "-U", user, "-d", name, "-f", backup_path]
58+
59+
try:
60+
env = os.environ.copy()
61+
env["PGPASSWORD"] = password
62+
63+
self.stdout.write(f"Dropping database {name}...")
64+
subprocess.run(drop_cmd, env=env, check=True)
65+
66+
self.stdout.write(f"Creating database {name}...")
67+
subprocess.run(create_cmd, env=env, check=True)
68+
69+
self.stdout.write("Restoring from backup...")
70+
subprocess.run(restore_cmd, env=env, check=True)
71+
72+
self.stdout.write(self.style.SUCCESS(f"Successfully restored {server.value} database from {backup_path}"))
73+
74+
except subprocess.CalledProcessError as e:
75+
self.stdout.write(self.style.ERROR(f"Restore failed on {server.value}: {str(e)}"))

0 commit comments

Comments
 (0)