Skip to content

Commit 0b3ed4f

Browse files
committed
django-azure-backup
0 parents  commit 0b3ed4f

24 files changed

+483
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
**/__pycache__/
2+
.idea/
3+
**/**/.env
4+
main_backup/.env

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Glib
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Glib Backup
2+
3+
This package can take postgres dump and able to upload data in azure cloud storage.
4+
5+
## Build Process
6+
open the link.
7+
[click here for steps.](https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives)
8+
9+
## Required
10+
1. Django Default Database Config.
11+
2. AZURE_ACCOUNT_NAME (Azure Storage Account Name).
12+
3. AZURE_CREDENTIAL (Azure Key).
13+
4. AZURE_CONTAINER (Azure Container Name).
14+
5. AZURE_BACKUP_FOLDER_NAME.

django_azure_backup/__init__.py

Whitespace-only changes.

django_azure_backup/admin.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.

django_azure_backup/apps.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class DjangoAzureBackupConfig(AppConfig):
5+
name = 'django_azure_backup'

django_azure_backup/db/__init__.py

Whitespace-only changes.

django_azure_backup/db/base.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import os
2+
import subprocess
3+
from django.conf import settings
4+
from azure.storage.blob import BlockBlobService
5+
6+
7+
class BackupSystem:
8+
9+
def __init__(self):
10+
self.blob_service_client: BlockBlobService
11+
default_config = settings.DATABASES.get('default')
12+
self.postgres_host = default_config.get('HOST')
13+
self.postgres_port = default_config.get('PORT')
14+
self.postgres_db = default_config.get('NAME')
15+
self.postgres_user = default_config.get('USER')
16+
self.postgres_password = default_config.get('PASSWORD')
17+
self.azure_credential = settings.AZURE_CREDENTIAL
18+
self.azure_container = settings.AZURE_CONTAINER
19+
self.azure_account_name = settings.AZURE_ACCOUNT_NAME
20+
self.azure_backup_folder_name = settings.AZURE_BACKUP_FOLDER_NAME
21+
self.blob_service_client = BlockBlobService(account_name=self.azure_account_name,
22+
account_key=self.azure_credential)
23+
24+
def get_list_of_blobs(self):
25+
return self.blob_service_client.list_blobs(container_name=self.azure_container,
26+
prefix=self.azure_backup_folder_name + '/')
27+
28+
def download_blob_file(self, name):
29+
return self.blob_service_client.get_blob_to_bytes(container_name=self.azure_container,
30+
blob_name=self.azure_backup_folder_name + "/" + name).content
31+
32+
def upload_blob_file(self, name, data):
33+
self.blob_service_client.create_blob_from_bytes(container_name=self.azure_container,
34+
blob_name=self.azure_backup_folder_name + "/" + name,
35+
blob=data)
36+
37+
def backup_postgres_db(self, verbose):
38+
"""
39+
Backup postgres db to a file.
40+
"""
41+
if verbose:
42+
try:
43+
process = subprocess.Popen(
44+
['pg_dump',
45+
'-Fc',
46+
'-v'],
47+
shell=True,
48+
env={
49+
'PGUSER': self.postgres_user,
50+
'PGPASSWORD': self.postgres_password,
51+
'PGDATABASE': self.postgres_db,
52+
'PGPORT': str(self.postgres_port),
53+
'PGHOST': self.postgres_host
54+
},
55+
stdout=subprocess.PIPE
56+
)
57+
output = process.communicate()[0]
58+
if int(process.returncode) != 0:
59+
print('Command failed. Return code : {}'.format(process.returncode))
60+
exit(1)
61+
return output
62+
except Exception as e:
63+
print(e)
64+
exit(1)
65+
else:
66+
print('{}:{}@{}:{}/{}'.format(self.postgres_user,
67+
self.postgres_password,
68+
self.postgres_host,
69+
self.postgres_port,
70+
self.postgres_db))
71+
try:
72+
process = subprocess.Popen(
73+
['pg_dump',
74+
'-Fc'],
75+
shell=True,
76+
env={
77+
'PGUSER': self.postgres_user,
78+
'PGPASSWORD': self.postgres_password,
79+
'PGDATABASE': self.postgres_db,
80+
'PGPORT': str(self.postgres_port),
81+
'PGHOST': self.postgres_host
82+
},
83+
stdout=subprocess.PIPE
84+
)
85+
output = process.communicate()[0]
86+
if process.returncode != 0:
87+
print('Command failed. Return code : {}'.format(process.returncode))
88+
exit(1)
89+
return output
90+
except Exception as e:
91+
print(e)
92+
exit(1)
93+
94+
def restore_postgres_db(self, filepath):
95+
"""Restore postgres db from a file."""
96+
try:
97+
d = dict(os.environ)
98+
d['PGPASSFILE'] = filepath
99+
d['PGPASSWORD'] = self.postgres_password
100+
host = self.postgres_host
101+
102+
process = subprocess.Popen(['psql',
103+
"-f%s" % filepath,
104+
"-d%s" % self.postgres_db,
105+
"-h%s" % host,
106+
"-U%s" % self.postgres_user
107+
], env=d,
108+
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
109+
)
110+
process.wait()
111+
if process.returncode != 0:
112+
print('Command failed. Return code : {}'.format(process.returncode))
113+
exit(1)
114+
return process.returncode
115+
except Exception as e:
116+
print("Issue with the db restore : {}".format(e))

django_azure_backup/management/__init__.py

Whitespace-only changes.

django_azure_backup/management/commands/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from ...db.base import BackupSystem
2+
import datetime
3+
from django.core.management.base import BaseCommand
4+
import argparse
5+
import configparser
6+
7+
8+
class Command(BaseCommand):
9+
10+
def handle(self, **options):
11+
print('checking configuration')
12+
backup_service = BackupSystem()
13+
print('Backup file list: --\n')
14+
for backup_file in backup_service.get_list_of_blobs():
15+
print(backup_file.name)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from ...db.base import BackupSystem
2+
import datetime
3+
from django.core.management.base import BaseCommand
4+
5+
6+
class Command(BaseCommand):
7+
8+
def handle(self, **options):
9+
print('checking configuration')
10+
backup_service = BackupSystem()
11+
print('creating psql dump')
12+
datafile = backup_service.backup_postgres_db(True)
13+
file_name = str(datetime.datetime.now().strftime('%Y-%m-%d-%M-%S')) + \
14+
"-" + backup_service.postgres_db + ".psql"
15+
print('uploading psql dump to azure container')
16+
backup_service.upload_blob_file(name=file_name, data=datafile)
17+
print('successfully uploaded file name: {}'.format(file_name))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import os
2+
from ...db.base import BackupSystem
3+
from django.core.management.base import BaseCommand
4+
5+
6+
class Command(BaseCommand):
7+
def add_arguments(self, parser):
8+
parser.add_argument('-n', "--name", type=ascii, help='blob file name dont add backup folder name')
9+
10+
def handle(self, **options):
11+
filename = options['name'][1:-1]
12+
print(filename)
13+
print('checking configuration')
14+
backup_service = BackupSystem()
15+
print('downloading backup file')
16+
obj_file = backup_service.download_blob_file(name=filename)
17+
with open('/tmp/' + filename, 'wb') as file_writer:
18+
file_writer.write(obj_file)
19+
print('restoring')
20+
backup_service.restore_postgres_db(filepath='/tmp/'+filename)
21+
print('restoring completed')
22+
try:
23+
print('removing temp file')
24+
os.remove('/tmp/' + filename)
25+
except:
26+
print('unable to delete file')
27+
print('request completed')

django_azure_backup/migrations/__init__.py

Whitespace-only changes.

django_azure_backup/models.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.db import models
2+
3+
# Create your models here.

django_azure_backup/tests.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.

django_azure_backup/views.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.shortcuts import render
2+
3+
# Create your views here.

main_backup/__init__.py

Whitespace-only changes.

main_backup/asgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
ASGI config for rewaflux project.
3+
4+
It exposes the ASGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.asgi import get_asgi_application
13+
14+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'main_backup.settings')
15+
16+
application = get_asgi_application()

0 commit comments

Comments
 (0)